<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Unity · Game Developer</title><link>https://gamedeveloper.com.br/categories/unity/</link><description>Unity · Desenvolvimento de jogos por Bruno Cicanci</description><generator>Hugo</generator><language>pt-BR</language><copyright>© 2009–2026 Game Developer por Bruno Cicanci. Todos os direitos reservados.</copyright><lastBuildDate>Mon, 15 Dec 2025 00:00:00 +0000</lastBuildDate><atom:link href="https://gamedeveloper.com.br/categories/unity/rss.xml" rel="self" type="application/rss+xml"/><item><title>Git no Unity: Como configurar um repositório do zero</title><link>https://gamedeveloper.com.br/git-no-unity/</link><guid>https://gamedeveloper.com.br/git-no-unity/</guid><pubDate>Mon, 15 Dec 2025 00:00:00 +0000</pubDate><category>Unity</category><description>Neste post você vai aprender como configurar um repositório Git em projetos Unity, seja antes de iniciar um novo projeto ou em um projeto já existente.&#10;</description><content:encoded>&lt;p&gt;Neste post você vai aprender como configurar um repositório Git em projetos Unity, seja antes de iniciar um novo projeto ou em um projeto já existente.&lt;/p&gt;&#10;&lt;p&gt;No vídeo, explico o passo a passo da configuração, compartilho boas práticas e dicas importantes para trabalhar com controle de versão e mostro como o mesmo processo funciona no GitHub, podendo ser adaptado facilmente para GitLab e Bitbucket.&lt;/p&gt;&#10;&lt;p&gt;Assista ao vídeo abaixo para acompanhar o tutorial completo.&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/pBfsTT2K6p4" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;Links mencionados no vídeo:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a href="https://git-scm.com" target="_blank" rel="noreferrer"&gt;Site oficial do git&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://www.sourcetreeapp.com" target="_blank" rel="noreferrer"&gt;Software visual para git: Sourcetree&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://www.gitkraken.com" target="_blank" rel="noreferrer"&gt;Software visual para git: GitKraken&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://github.com" target="_blank" rel="noreferrer"&gt;Repositórios git: GitHub&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://gitlab.com" target="_blank" rel="noreferrer"&gt;Repositórios git: GitLab&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://bitbucket.org" target="_blank" rel="noreferrer"&gt;Repositórios git: BitBucket&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://git-lfs.com" target="_blank" rel="noreferrer"&gt;Arquivos grandes com Git LFS&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Mais conteúdo sobre git:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a href="https://gamedeveloper.com.br/unity-git-lfs/" target="_blank" rel="noreferrer"&gt;Git e LFS em projetos Unity&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://gamedeveloper.com.br/introducao-ao-github-guia-nao-tecnico/" target="_blank" rel="noreferrer"&gt;Introdução ao GitHub: um guia que não é técnico&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://gamedeveloper.com.br/git-usando-branches/" target="_blank" rel="noreferrer"&gt;Modelo de desenvolvimento com GIT usando branches&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://gamedeveloper.com.br/git-alias/" target="_blank" rel="noreferrer"&gt;Como criar atalhos com git alias&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/images/2025/12/titulo-unity-git.webp" medium="image"/></item><item><title>Minha participação na Unite 2025 em Barcelona</title><link>https://gamedeveloper.com.br/unity-unite-2025/</link><guid>https://gamedeveloper.com.br/unity-unite-2025/</guid><pubDate>Mon, 24 Nov 2025 00:00:00 +0000</pubDate><category>Unity</category><description>Unite é o evento anual da game engine Unity, que aconteceu este ano novamente em Barcelona, entre os dias 17 e 20 de Novembro. Foi minha primeira vez no evento, e tive a honra de participar não apenas como espectador, mas também como palestrante e Unity Insider.&#10;</description><content:encoded>&lt;p&gt;&lt;a href="https://unity.com/events/unite" target="_blank" rel="noreferrer"&gt;Unite&lt;/a&gt; é o evento anual da game engine &lt;a href="https://unity.com" target="_blank" rel="noreferrer"&gt;Unity&lt;/a&gt;, que aconteceu este ano novamente em Barcelona, entre os dias 17 e 20 de Novembro. Foi minha primeira vez no evento, e tive a honra de participar não apenas como espectador, mas também como &lt;a href="https://www.unite-registration.com/flow/unity/unite25/sessionCatalogue/page/page/session/1748860246014001ryIw" target="_blank" rel="noreferrer"&gt;palestrante&lt;/a&gt; e &lt;em&gt;&lt;strong&gt;Unity Insider&lt;/strong&gt;&lt;/em&gt;.&lt;/p&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt="Unity x Epic"&#10; src="https://gamedeveloper.com.br/images/2025/11/unity-epic.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;p&gt;O título da minha palestra foi &lt;em&gt;&lt;strong&gt;Reusable technology: Saving development time with shared Unity plug-ins and SDKs&lt;/strong&gt;&lt;/em&gt;, onde compartilhei como desenvolvemos SDKs para Android e iOS, plugins para Unity, e como testamos e publicamos. Este é parte do trabalho que minha equipe realiza na Ubisoft, e foi uma experiência incrível compartilhar isso no maior evento da Unity. Vou fazer outro post sobre a minha palestra quando a gravação for publicada no canal da &lt;a href="https://www.youtube.com/@unity/" target="_blank" rel="noreferrer"&gt;Unity no YouTube&lt;/a&gt;, e comentar mais sobre o assunto.&lt;/p&gt;&#10;&lt;p&gt;Além de palestrar, também participei de um encontro com outros membros do programa &lt;a href="https://unity.com/unity-insiders" target="_blank" rel="noreferrer"&gt;Unity Insiders&lt;/a&gt;, do qual faço parte desde 2022. Também vou escrever outro post sobre este programa e os criadores de conteúdo que conheci pessoalmente no evento.&lt;/p&gt;&#10;&lt;p&gt;Neste post, quero destacar alguns anúncios do Keynote, a inesperada parceria entre Unity e Unreal, e o Roadmap da game engine para o próximo ano.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;Keynote&#10; &lt;div id="keynote" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#keynote" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;O grande destaque do keynote deste ano foi a ausência de produtos e serviços baseados em Inteligência Artificial generativa, o que considero um ponto muito positivo. Tudo que foi apresentado no keynote, e depois detalhado no roadmap, mostra que a Unity está focada nos desenvolvedores de jogos e em tornar sua engine uma ferramenta sólida, ao invés de seguir o hype da I.A. para agradar acionistas.&lt;/p&gt;&#10;&lt;p&gt;Alguns jogos feitos com Unity lançados este ano foram apresentados, com destaque para &lt;a href="https://store.steampowered.com/app/2133760/Tiny_Bookshop/" target="_blank" rel="noreferrer"&gt;Tiny Bookshop&lt;/a&gt;, &lt;a href="https://store.steampowered.com/app/3405340/Megabonk/" target="_blank" rel="noreferrer"&gt;Megabonk&lt;/a&gt; e &lt;a href="https://store.steampowered.com/app/3527290/PEAK/" target="_blank" rel="noreferrer"&gt;Peak&lt;/a&gt;. Os desenvolvedores de Peak subiram ao palco para compartilhar como conseguiram criar um jogo em apenas 10 semanas, com 7 desenvolvedores, e que já vendeu mais de 10 milhões de cópias. Eles enfatizaram a facilidade de prototipar e iterar utilizando a engine.&lt;/p&gt;&#10;&lt;p&gt;Outro dado interessante apresentado foi que 70% dos jogos para dispositivos móveis são feitos utilizando Unity, o que demonstra a dominância desta game engine nesta plataforma. Além disso, 33% dos jogos no Steam são feitos com Unity, e na web o número é de aproximadamente 50%. Não foram mostrados dados para consoles, mas acredito que sejam inferiores aos do Steam, caso contrário teriam sido apresentados.&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/MXsKt7JqX5M" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;Durante o keynote, foi apresentado que a Unity consolidou seus esforços em três categorias que representam o ciclo de vida de um projeto: &lt;em&gt;Develop&lt;/em&gt; (Desenvolver), &lt;em&gt;Deploy&lt;/em&gt; (Lançar), e &lt;em&gt;Grow&lt;/em&gt; (Crescer). Cada novo serviço, funcionalidade ou melhoria apresentada durante o evento está dentro destas categorias. Abaixo, fiz um resumo de algumas novidades que estão por vir.&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;Develop&#10; &lt;div id="develop" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#develop" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;Em parceria com a Konami, a Unity desenvolveu e lançou um jogo para Switch 2, o &lt;a href="https://www.konami.com/games/survival_kids/" target="_blank" rel="noreferrer"&gt;Survival Kids&lt;/a&gt;, o que permitiu observar de perto a utilização da engine para criar um jogo do início ao fim, além de adicionar suporte ao Switch 2 no lançamento.&lt;/p&gt;&#10;&lt;p&gt;Este jogo foi desenvolvido pela Unity Studios, e mais jogos serão lançados para ajudar a aprimorar a engine. Levou quase 20 anos para a Unity perceber que, ao utilizar sua própria engine, poderiam entender melhor as necessidades dos desenvolvedores. Isso também faz parte de outra iniciativa da Unity, chamada &lt;em&gt;Production Verification&lt;/em&gt;, onde garantem que uma versão da Unity foi utilizada e verificada por eles mesmos em produção (ou seja, lançaram um jogo).&lt;/p&gt;&#10;&lt;p&gt;Ao que tudo indica, a Unity 7 (ou o que estava sendo chamado de Unity 7 até então) foi &amp;quot;cancelada&amp;quot;. Em vez de uma nova versão, a Unity lançará versões incrementais da Unity 6 (semelhante ao ciclo de lançamento da Unreal). A Unity 6.3 LTS acabou de ser lançada, e no final de 2026 teremos a Unity 6.7 LTS, sendo que as versões lançadas entre estas duas (6.4, 6.5, 6.6) trarão melhorias, mas sem o &lt;em&gt;Long Time Support&lt;/em&gt; (LTS).&lt;/p&gt;&#10;&lt;p&gt;Outras novidades incluem uma nova ferramenta para utilizar modelos 3D em jogos 2D (não é 2.5D), a validação de pacotes instalados pelo &lt;em&gt;Package Manager&lt;/em&gt; com uma assinatura que garante a autenticidade deles, entre outras melhorias detalhadas no vídeo do roadmap.&lt;/p&gt;&#10;&lt;p&gt;Outro destaque é a migração do .Net para o Core CLR, que deve melhorar várias áreas da engine, como redução do tempo de compilação (projetos com mais de 50% de redução), suporte a versões mais novas do C#, e maior estabilidade para o editor. A migração está prevista para começar na versão 6.4 e ser concluída na versão 6.7.&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;Deploy&#10; &lt;div id="deploy" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#deploy" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;O principal destaque aqui foi o &lt;em&gt;Platform Toolkit&lt;/em&gt;, um novo pacote da Unity que promete acelerar a publicação de jogos em diversas plataformas. Os desenvolvedores precisarão de apenas uma API para cada funcionalidade específica das plataformas, como conquistas, e a Unity garantirá que isso funcione em todas as plataformas suportadas, sem necessidade de alterações no código.&lt;/p&gt;&#10;&lt;p&gt;Outra promessa é que isso deve ajudar no processo de certificação dos jogos para lançamento em consoles, um processo complexo e exigente. Com este novo pacote, a Unity busca facilitar o lançamento de jogos em mais plataformas, reduzindo ou até eliminando complexidades específicas de cada uma.&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;Grow&#10; &lt;div id="grow" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#grow" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;A Unity apresentou uma nova ferramenta chamada &lt;em&gt;Vector AI&lt;/em&gt;, que analisa o mercado e os dados do jogo para oferecer direções e sugestões para aumentar o engajamento dos jogadores. Esta foi provavelmente a única menção a uma ferramenta utilizando I.A., e parece ser uma ideia promissora, especialmente para pequenos estúdios e desenvolvedores independentes que não possuem equipes dedicadas para coleta e análise de dados.&lt;/p&gt;&#10;&lt;p&gt;Outra novidade é uma ferramenta para &lt;em&gt;In-App Purchase&lt;/em&gt; (compras dentro do jogo), que permite a utilização de meios de pagamento de terceiros, como Stripe e Coda, além de uma ferramenta para gerenciar o inventário do jogador. Graças ao processo da Epic contra o monopólio da Apple e Google em suas lojas digitais, o suporte a meios de pagamento de terceiros está se tornando mais comum em jogos para dispositivos móveis.&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;Unity x Epic&#10; &lt;div id="unity-x-epic" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#unity-x-epic" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/eDdWSJ5A04E" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;O momento mais surpreendente do evento foi, sem dúvidas, o anúncio da inédita parceria entre Unity e Epic, com os CEOs de cada empresa no palco. A parceria permitirá que desenvolvedores na Unreal utilizem a nova ferramenta de &lt;em&gt;In-App Purchase&lt;/em&gt; da Unity, provavelmente disponibilizando um plugin para Unreal e permitindo o acesso ao serviço.&lt;/p&gt;&#10;&lt;p&gt;Além disso, foi anunciado que jogos feitos com a Unity poderão ser lançados dentro do ecossistema do Fortnite. Detalhes ainda não foram anunciados, mas estou curioso para saber como isso funcionará. Sem dúvidas, isso abre um novo mercado para jogos feitos com Unity, beneficiando desenvolvedores e jogadores.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;Roadmap&#10; &lt;div id="roadmap" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#roadmap" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;Além do keynote, por enquanto o único vídeo publicado do evento foi o roadmap abaixo, que mostra em detalhes tudo que foi mencionado no keynote.&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/rEKmARCIkSI" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;Como o vídeo acima aborda basicamente o mesmo assunto do keynote, porém com muito mais detalhes, não vou escrever sobre a apresentação em si.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;Conclusão&#10; &lt;div id="conclusão" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#conclus%c3%a3o" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;Fiquei feliz pela ausência de I.A. generativa e por ver que a Unity está levando a sério melhorias na engine com os desenvolvedores em mente. Após o fiasco do &lt;em&gt;runtime fee&lt;/em&gt; (cancelado) e a troca de CEO, a Unity parece estar focada em tornar sua engine mais estável, com funcionalidades e serviços alinhados às necessidades dos desenvolvedores.&lt;/p&gt;&#10;&lt;p&gt;Esta foi minha primeira vez no Unite, e também a primeira vez apresentando uma palestra em Inglês. Fiquei feliz de participar do evento como palestrante, insider, e por reencontrar amigos e colegas de trabalho. Isso me faz lembrar que a indústria de jogos é &amp;quot;pequena&amp;quot; e sempre reencontramos pessoas ou conhecemos alguém com contatos em comum.&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/categories/unity.webp" medium="image"/></item><item><title>Como implementar o padrão Message Queue no Unity</title><link>https://gamedeveloper.com.br/message-queue-pattern-unity/</link><guid>https://gamedeveloper.com.br/message-queue-pattern-unity/</guid><pubDate>Mon, 03 Feb 2025 00:00:00 +0000</pubDate><category>Unity</category><description>O padrão Message Queue é uma maneira simples e eficiente de desacoplar o código no seu projeto de jogo. Uma das formas mais fáceis e eficazes de desacoplar o código em um jogo é implementando o padrão Message Queue, também conhecido como Event Queue.&#10;</description><content:encoded>&lt;p&gt;O padrão Message Queue é uma maneira simples e eficiente de desacoplar o código no seu projeto de jogo. Uma das formas mais fáceis e eficazes de desacoplar o código em um jogo é implementando o padrão Message Queue, também conhecido como &lt;a href="https://gameprogrammingpatterns.com/event-queue.html" target="_blank" rel="noreferrer"&gt;Event Queue&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p&gt;Esse padrão consiste em enviar mensagens quando você deseja atualizar algo na interface do jogo, por exemplo, sem precisar manter uma referência direta ao objeto da interface ou utilizar um padrão Singleton para expor acesso a ele. Em vez disso, a interface escutará o tipo de mensagem necessário para atualizar a interface, e essa mensagem será enviada apenas quando um sistema do jogo precisar atualizar a interface.&lt;/p&gt;&#10;&lt;p&gt;Vamos dividir o padrão Message Queue em três partes: o gerenciador da fila, responsável pela fila em si; a mensagem, que contém o que queremos enviar; e os ouvintes, que ficam esperando a mensagem para executar alguma ação assim que a receberem.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;O gerenciador Message Queue&#10; &lt;div id="o-gerenciador-message-queue" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#o-gerenciador-message-queue" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;O núcleo do padrão Message Queue é uma classe responsável por armazenar uma lista de ouvintes, além de adicionar e remover ouvintes e enviar mensagens para cada ouvinte que estiver escutando um tipo específico de mensagem.&lt;/p&gt;&#10;&lt;p&gt;No código abaixo, criamos nossa classe MessageQueue e definimos um Dictionary para armazenar nossos ouvintes, organizando-os por tipo. Cada Type possui uma List de Delegate, que são callbacks executados quando um tipo específico de mensagem é recebido.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageQueue&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Delegate&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_listeners&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;MessageQueue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_listeners&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Delegate&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Em seguida, adicionamos métodos à nossa classe MessageQueue. O primeiro é o AddListener, que tem o tipo genérico T para o parâmetro listener.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;AddListener&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_listeners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TryGetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Delegate&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;listeners&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Delegate&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_listeners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;O próximo método é o RemoveListener, que remove um ouvinte da lista e, caso a lista fique vazia, a remove do Dictionary.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;RemoveListener&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_listeners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TryGetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Delegate&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_listeners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Por fim, o método SendMessage encontra uma lista de ouvintes aguardando um tipo de mensagem e chama cada um como callback, passando a mensagem como parâmetro.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;SendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_listeners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TryGetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetType&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="k"&gt;out&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Delegate&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;DynamicInvoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&#10;&lt;h2 class="relative group"&gt;O objeto Message&#10; &lt;div id="o-objeto-message" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#o-objeto-message" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;O objeto mensagem pode ser qualquer classe. No exemplo abaixo, criamos uma classe que representa uma mensagem contendo uma propriedade NewColor.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UpdateColorMessage&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="n"&gt;NewColor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&#10;&lt;h2 class="relative group"&gt;O uso dos ouvintes&#10; &lt;div id="o-uso-dos-ouvintes" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#o-uso-dos-ouvintes" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;A classe MessageQueueExample é um MonoBehaviour que pode ser adicionado a qualquer GameObject no Unity. Ela usa o MessageQueue para adicionar e remover um callback.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageQueueExample&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;MessageQueue&lt;/span&gt; &lt;span class="n"&gt;_messageQueue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MessageQueue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;OnEnable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_messageQueue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddListener&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UpdateColorMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;UpdateColor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;OnDisable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_messageQueue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RemoveListener&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;UpdateColorMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;UpdateColor&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;UpdateColor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;UpdateColorMessage&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Use o message.NewColor para atualizar a cor&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Os métodos OnEnable e OnDisable são executados uma vez pelo Unity, garantindo que os ouvintes sejam sempre adicionados e removidos corretamente.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;Enviando mensagens&#10; &lt;div id="enviando-mensagens" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#enviando-mensagens" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;Abaixo estão três métodos que enviam mensagens para mudar a cor para vermelho, verde e azul.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;ChangeColorToRed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;UpdateColorMessage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;NewColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;red&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_messageQueue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;ChangeColorToGreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;UpdateColorMessage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;NewColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;green&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_messageQueue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;ChangeColorToBlue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;UpdateColorMessage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;NewColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blue&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_messageQueue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Cada método cria uma instância de UpdateColorMessage e define a propriedade NewColor antes de enviar a mensagem aos ouvintes.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;Conclusão&#10; &lt;div id="conclusão" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#conclus%c3%a3o" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;O padrão Message Queue é muito poderoso para desacoplar o código e facilitar a comunicação entre sistemas usando mensagens. Espero que este artigo tenha ajudado você a entender como implementá-lo usando C# no Unity.&lt;/p&gt;&#10;&lt;p&gt;O código deste artigo, assim como um exemplo completo implementado no Unity, pode ser encontrado no meu &lt;a href="https://github.com/cicanci/game-programming-patterns/tree/main/Assets/Scripts/DecouplingPatterns/MessageQueue" target="_blank" rel="noreferrer"&gt;repositório do GitHub&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p&gt;Você já utilizou esse padrão em algum projeto? Compartilhe sua experiência nos comentários e me avise se tiver alguma dúvida!&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/categories/unity.webp" medium="image"/></item><item><title>Meu primeiro livro: Criando um Jogo RTS na Unity 2023</title><link>https://gamedeveloper.com.br/creating-an-rts-game-in-unity/</link><guid>https://gamedeveloper.com.br/creating-an-rts-game-in-unity/</guid><pubDate>Sun, 01 Oct 2023 00:00:00 +0000</pubDate><category>Unity</category><description>Fiquei sem atualizar o blog nos últimos meses, e hoje posso compartilhar o motivo: escrevi meu primeiro livro!&#10;Da concepção à publição foram meses dedicando meu tempo livre para escrever um livro que combinasse minha experiência profissional de quase 14 anos desenvolvendo jogos, sendo 10 anos utilizando Unity como minha principal engine. Foi uma oportunidade incrível e que não seria possível sem a editora Packt para me apoiar e fornecer o suporter necessário para revisão de textos, código, e muito mais.&#10;</description><content:encoded>&lt;p&gt;Fiquei sem atualizar o blog nos últimos meses, e hoje posso compartilhar o motivo: escrevi meu primeiro livro!&lt;/p&gt;&#10;&lt;p&gt;Da concepção à publição foram meses dedicando meu tempo livre para escrever um livro que combinasse minha experiência profissional de quase 14 anos desenvolvendo jogos, sendo 10 anos utilizando Unity como minha principal engine. Foi uma oportunidade incrível e que não seria possível sem a &lt;a href="https://www.packtpub.com/product/creating-an-rts-game-in-unity-2023/9781804613245" target="_blank" rel="noreferrer"&gt;editora Packt&lt;/a&gt; para me apoiar e fornecer o suporter necessário para revisão de textos, código, e muito mais.&lt;/p&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/book/book-cover.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;p&gt;Com pouco mais de 550 páginas, em Inglês, o livro vai te ensinar a fazer um jogo RTS na Unity 2023 utilizando C#. O foco do livro é criar um jogo RTS do início ao fim, porém, todo conteúdo do livro é facilmente aplicável a praticamente qualquer outro tipo jogo, já que muitos conceitos e algoritmos são os mesmos. Apesar de ter sido um desafio ainda maior pra mim, escrever o livro em Inglês possibilita que mais pessoas tenham acesso ao seu conteúdo.&lt;/p&gt;&#10;&lt;p&gt;O livro já está em pré-venda, e será lançado no próximo dia 13 de Outubro na &lt;a href="https://a.co/d/3FenKy3" target="_blank" rel="noreferrer"&gt;Amazon Brasil&lt;/a&gt; em todas as outras, inclindo algumas livrarias nos EUA e Reino Unido, e no próprio &lt;a href="https://www.packtpub.com/product/creating-an-rts-game-in-unity-2023/9781804613245" target="_blank" rel="noreferrer"&gt;side da editora&lt;/a&gt;. O livro estará disponível em formato digital (Kindle) e físico.&lt;/p&gt;&#10;&lt;p&gt;Abaixo está uma descrição do livro sobre o conteúdo. Ficarei feliz de responder qualquer pergunta sobre o livro e seu conteúdo, e agradesço desde já se você puder adquirir o livro.&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;Descrição do Livro&#10; &lt;div id="descrição-do-livro" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#descri%c3%a7%c3%a3o-do-livro" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;Construir um jogo de estratégia em tempo real de sucesso é desafiador, devido às mecânicas complexas e à necessidade de equilibrar diferentes elementos, garantindo que os jogadores desfrutem de criar e executar estratégias contra a inteligência artificial do jogo. &amp;quot;Creating an RTS game in Unity 2023&amp;quot; irá ensinar você a instalar e configurar o motor de jogo Unity, criar um novo projeto 3D e construir um editor de níveis para facilitar a modificação e adição de mapas ao jogo.&lt;/p&gt;&#10;&lt;p&gt;Ao longo do livro, o seu RTS começará a ganhar forma à medida que você aprender a implementar sistemas centrais, como batalhas corpo a corpo e à distância, geradores de unidades, controles de câmera, geração dinâmica de mapas, IA básica de inimigos e o algoritmo de pathfinding. Você também dominará a implementação de unidades de comando para executar ações, produção e gestão de recursos, física básica e detecção de colisões, tudo isso enquanto constrói um jogo de estratégia em tempo real do zero, utilizando C# e as últimas funcionalidades da Unity.&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;O Que Você Irá Aprender&#10; &lt;div id="o-que-você-irá-aprender" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#o-que-voc%c3%aa-ir%c3%a1-aprender" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Configuração do Unity e criação de projetos 3D.&lt;/li&gt;&#10;&lt;li&gt;Desenvolvimento de um editor de níveis personalizado.&lt;/li&gt;&#10;&lt;li&gt;Implementação de mecânicas de combate e unidades.&lt;/li&gt;&#10;&lt;li&gt;Controles de câmera envolventes para o jogador.&lt;/li&gt;&#10;&lt;li&gt;Geração dinâmica de mapas e IA de inimigos.&lt;/li&gt;&#10;&lt;li&gt;Algoritmo de pathfinding para movimentação eficiente das unidades.&lt;/li&gt;&#10;&lt;li&gt;Comandos de unidades para execução de ações estratégicas.&lt;/li&gt;&#10;&lt;li&gt;Gestão de recursos e produção de unidades.&lt;/li&gt;&#10;&lt;li&gt;Física e detecção de colisões para um gameplay realista.&lt;/li&gt;&#10;&lt;li&gt;Construção completa de um RTS usando C# e Unity.&lt;/li&gt;&#10;&lt;li&gt;Ao final deste livro, você estará apto a criar jogos de estratégia em tempo real profissionais e de alta qualidade, utilizando as melhores práticas e técnicas da indústria de jogos.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;PS: Comenta se você reconheceu a imagem da capa do livro, e se inscreva no meu &lt;a href="https://www.youtube.com/c/BrunoCicanci" target="_blank" rel="noreferrer"&gt;canal no YouTube&lt;/a&gt; por que muito contéudo novo está por vir!&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/book/book-banner-post.webp" medium="image"/></item><item><title>Desenvolvimento de jogos em Unity com TDD</title><link>https://gamedeveloper.com.br/unity-tdd/</link><guid>https://gamedeveloper.com.br/unity-tdd/</guid><pubDate>Sat, 04 Mar 2023 00:00:00 +0000</pubDate><category>Unity</category><description>Desenvolver jogos é um processo complexo e desafiador, mas o uso de técnicas de desenvolvimento de software pode ajudar a tornar esse processo mais eficiente e eficaz. Um desses métodos é o Test-Driven Development (TDD), que pode ser aplicado ao desenvolvimento de jogos com Unity.&#10;</description><content:encoded>&lt;p&gt;Desenvolver jogos é um processo complexo e desafiador, mas o uso de técnicas de desenvolvimento de software pode ajudar a tornar esse processo mais eficiente e eficaz. Um desses métodos é o Test-Driven Development (TDD), que pode ser aplicado ao desenvolvimento de jogos com Unity.&lt;/p&gt;&#10;&lt;p&gt;O TDD é um processo iterativo de desenvolvimento de software que consiste em escrever testes automatizados antes de escrever o código final. O processo começa com a escrita de um teste automatizado que falha e, em seguida, a escrita de código que faça o teste passar. Isso ajuda a garantir que o código escrito atenda aos requisitos definidos pelos testes e reduz o risco de erros e defeitos.&lt;/p&gt;&#10;&lt;p&gt;Ao usar o TDD no desenvolvimento de jogos com o Unity, é importante seguir algumas boas práticas recomendadas para garantir que o processo seja eficaz e eficiente.&lt;/p&gt;&#10;&#10;&lt;h4 class="relative group"&gt;Escreva testes para cada nova funcionalidade&#10; &lt;div id="escreva-testes-para-cada-nova-funcionalidade" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#escreva-testes-para-cada-nova-funcionalidade" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h4&gt;&#10;&lt;p&gt;Cada nova funcionalidade que você adiciona ao seu jogo deve ter seus próprios testes automatizados. Isso ajudará a garantir que o código funcione como esperado e que não há efeitos colaterais indesejados em outras partes do jogo.&lt;/p&gt;&#10;&#10;&lt;h4 class="relative group"&gt;Escreva testes para cada cenário de uso&#10; &lt;div id="escreva-testes-para-cada-cenário-de-uso" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#escreva-testes-para-cada-cen%c3%a1rio-de-uso" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h4&gt;&#10;&lt;p&gt;Além de testar cada nova funcionalidade, é importante testar cada cenário de uso do jogo. Por exemplo, se o jogo tiver uma fase em que o personagem precisa coletar moedas, é importante testar se todas as moedas são coletadas corretamente. Isso ajuda a garantir que o jogo seja jogável e livre de bugs.&lt;/p&gt;&#10;&#10;&lt;h4 class="relative group"&gt;Escreva testes para detectar erros comuns&#10; &lt;div id="escreva-testes-para-detectar-erros-comuns" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#escreva-testes-para-detectar-erros-comuns" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h4&gt;&#10;&lt;p&gt;Alguns erros são comuns no desenvolvimento de jogos com Unity, como erros de colisão e de controle de personagens. Escreva testes para detectar esses erros comuns e corrigi-los antes que eles se tornem problemas maiores.&lt;/p&gt;&#10;&#10;&lt;h4 class="relative group"&gt;Escreva testes antes de implementar o código final&#10; &lt;div id="escreva-testes-antes-de-implementar-o-código-final" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#escreva-testes-antes-de-implementar-o-c%c3%b3digo-final" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h4&gt;&#10;&lt;p&gt;O TDD requer que os testes sejam escritos antes do código final ser implementado. Isso ajuda a garantir que o código final atenda aos requisitos definidos pelos testes e ajuda a evitar a introdução de erros no código.&lt;/p&gt;&#10;&#10;&lt;h4 class="relative group"&gt;Execute testes automaticamente durante o processo de construção&#10; &lt;div id="execute-testes-automaticamente-durante-o-processo-de-construção" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#execute-testes-automaticamente-durante-o-processo-de-constru%c3%a7%c3%a3o" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h4&gt;&#10;&lt;p&gt;Os testes automatizados devem ser executados automaticamente durante o processo de construção do jogo. Isso ajuda a garantir que todas as alterações no código sejam testadas e que nenhum erro seja introduzido no código existente.&lt;/p&gt;&#10;&#10;&lt;h4 class="relative group"&gt;Refatore o código à medida que novos testes são adicionados&#10; &lt;div id="refatore-o-código-à-medida-que-novos-testes-são-adicionados" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#refatore-o-c%c3%b3digo-%c3%a0-medida-que-novos-testes-s%c3%a3o-adicionados" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h4&gt;&#10;&lt;p&gt;À medida que novos testes são adicionados, pode ser necessário refatorar o código existente para que ele atenda aos requisitos dos novos testes. Isso ajuda a garantir que o código seja fácil de manter e que não haja erros ou problemas de desempenho.&lt;/p&gt;&#10;&lt;p&gt;O uso do TDD no desenvolvimento de jogos com Unity pode ajudar a garantir que o jogo seja jogável, livre de erros e fácil de manter. Ao seguir as práticas recomendadas acima, você pode maximizar os benefícios do TDD e tornar o processo de desenvolvimento de jogos mais eficiente e eficaz.&lt;/p&gt;&#10;&lt;p&gt;Devo admitir que TDD é algo que está na minha lista para me aperfeiçoar a anos, e ainda não saí do básico que é criar os testes na Unity e tentar lembrar de rodar eles. Por isso automatizar os testes com Integração Contínua (CI) ou adicionar um script que obrigue rodar os testes antes de um &lt;code&gt;git push&lt;/code&gt; pode ajudar a introduzir o uso do TDD cada vez mais ao dia-a-dia.&lt;/p&gt;&#10;&lt;p&gt;Mas cuidado, o TDD não pode ser visto como uma barreira que atrasa o desenvolvimento - apenas entendendo e usando o TDD pensando sempre na qualidade do código pode fazer ver seu uso mais como uma garantia bem-vinda do que um empecílio.&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/categories/unity.webp" medium="image"/></item><item><title>Como exibir um README na Unity ao abrir o projeto</title><link>https://gamedeveloper.com.br/unity-readme/</link><guid>https://gamedeveloper.com.br/unity-readme/</guid><pubDate>Sat, 16 Apr 2022 00:00:00 +0000</pubDate><category>Unity</category><description>Uma forma interessante de exibir uma mensagem de boas vindas ou informações sobre o projeto ao ser carregado é exibir um conteúdo similar à um arquivo README que pode ser customizado e exibido na janela do inspector dentro do editor da Unity. Neste vídeo eu mostro como criar um ScriptableObject, alterar sua visualização utilizando um CustomEditor e, por fim, colocar o foco do projeto e do inspector neste arquivo ao carregar o projeto na Unity.&#10;</description><content:encoded>&lt;p&gt;Uma forma interessante de exibir uma mensagem de boas vindas ou informações sobre o projeto ao ser carregado é exibir um conteúdo similar à um arquivo README que pode ser customizado e exibido na janela do inspector dentro do editor da Unity. Neste vídeo eu mostro como criar um &lt;code&gt;ScriptableObject&lt;/code&gt;, alterar sua visualização utilizando um &lt;code&gt;CustomEditor&lt;/code&gt; e, por fim, colocar o foco do projeto e do inspector neste arquivo ao carregar o projeto na Unity.&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/dKD4PXOdcyE" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;Abaixo estão os códigos das duas classes criadas no vídeo como referência, &lt;code&gt;Readme&lt;/code&gt; e &lt;code&gt;ReadEditor&lt;/code&gt;, respectivamente.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;[CreateAssetMenu(fileName = &amp;#34;Readme&amp;#34;, menuName = &amp;#34;Create Readme&amp;#34;)]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Readme&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ScriptableObject&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Sections&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEditor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;[CustomEditor(typeof(Readme))]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;[InitializeOnLoad]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReadmeEditor&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Editor&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;ReadmeEditor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;EditorApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delayCall&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;SelectReadme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;SelectReadme&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;EditorApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delayCall&lt;/span&gt; &lt;span class="p"&gt;-=&lt;/span&gt; &lt;span class="n"&gt;SelectReadme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;readmeObject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Resources&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Readme&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Readme&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readmeObject&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;EditorUtility&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FocusProjectWindow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Selection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;activeObject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;readmeObject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;OnHeaderGUI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Readme&lt;/span&gt; &lt;span class="n"&gt;readme&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Readme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;GUILayout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BeginHorizontal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GUI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;skin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;label&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fontSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;GUILayout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;readme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;GUILayout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EndHorizontal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;OnInspectorGUI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Readme&lt;/span&gt; &lt;span class="n"&gt;readme&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Readme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;section&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;readme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sections&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GUI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;skin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;label&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fontSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wordWrap&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;GUILayout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;GUILayout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Space&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;18&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Veja a playlist do canal com mais vídeos sobre Unity &lt;a href="https://www.youtube.com/playlist?list=PLIDWyOQe6ONuhQrhN6YmTASLNlzRPuraR" target="_blank" rel="noreferrer"&gt;clicando aqui&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p&gt;Dúvidas, comentários ou sugestões para futuros vídeos deixem aqui no post ou lá no vídeo no YouTube.&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/images/2022/04/unity-readme.webp" medium="image"/></item><item><title>Como adicionar e utilizar botões na Unity</title><link>https://gamedeveloper.com.br/unity-ui-button/</link><guid>https://gamedeveloper.com.br/unity-ui-button/</guid><pubDate>Sat, 15 Jan 2022 00:00:00 +0000</pubDate><category>Unity</category><description>Neste vídeo demonstro como criar um botão na interaface da Unity, algumas customizações que podem ser aplicadas nele, e como executar um script a partir do evento OnClick. Além de um script, também mostro como executar métodos de outros objetos da Unity no OnClick.&#10;</description><content:encoded>&lt;p&gt;Neste vídeo demonstro como criar um botão na interaface da Unity, algumas customizações que podem ser aplicadas nele, e como executar um script a partir do evento OnClick. Além de um script, também mostro como executar métodos de outros objetos da Unity no OnClick.&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/rgoSnyu5bF0" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;Veja a playlist do canal com mais vídeos sobre Unity &lt;a href="https://www.youtube.com/playlist?list=PLIDWyOQe6ONuhQrhN6YmTASLNlzRPuraR" target="_blank" rel="noreferrer"&gt;clicando aqui&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p&gt;Dúvidas, comentários ou sugestões para futuros vídeos deixem aqui no post ou lá no vídeo no YouTube.&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/images/2022/01/unity-ui-button.webp" medium="image"/></item><item><title>Utilizando Object Pool pattern na Unity</title><link>https://gamedeveloper.com.br/object-pool-unity/</link><guid>https://gamedeveloper.com.br/object-pool-unity/</guid><pubDate>Fri, 24 Dec 2021 00:00:00 +0000</pubDate><category>Unity</category><description>Neste vídeo mostro um exemplo de como utilizar o design patter Object Pool para reutilizar game objects em situações onde várias cópias são necessárias, como tiros ou inimigos, porém utilizando este design pattern para garantir um bom uso de memória.&#10;</description><content:encoded>&lt;p&gt;Neste vídeo mostro um exemplo de como utilizar o &lt;a href="https://gameprogrammingpatterns.com/object-pool.html" target="_blank" rel="noreferrer"&gt;design patter Object Pool&lt;/a&gt; para reutilizar game objects em situações onde várias cópias são necessárias, como tiros ou inimigos, porém utilizando este design pattern para garantir um bom uso de memória.&lt;/p&gt;&#10;&lt;p&gt;A ideia do Object Pool é ter um conjunto de objetos na memória que podem ser reutilizados. Na sua inicialização, um número pré-determinado de objetos são instanciados e ficam disponíveis porém não habilitados. Quando um objeto é requisitado, ele é habilitado e fica indisponível neste conjunto. E, quando não é mais necessário, ele fica desabilitado ao invés de ser destruído para que possa ser utilizado novamente.&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/0--XpK0NdKs" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;O projeto do vídeo está &lt;a href="https://github.com/cicanci/unity-object-pool-sample" target="_blank" rel="noreferrer"&gt;disponível neste repositório no meu GitHub&lt;/a&gt;. Dúvidas, comentários ou sugestões para futuros vídeos deixem aqui no post ou lá no vídeo no YouTube.&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/images/2021/12/object-pool-unity.webp" medium="image"/></item><item><title>Como fazer um sistema de build na Unity</title><link>https://gamedeveloper.com.br/sistema-build-unity/</link><guid>https://gamedeveloper.com.br/sistema-build-unity/</guid><pubDate>Sat, 18 Dec 2021 00:00:00 +0000</pubDate><category>Unity</category><description>A Unity possui um sistema de build onde você pode exportar seu projeto para diferentes plataformas e otimizaçoes. Este sistema é um pouco limitado quando utilizado através da interface do Editor, porém ele possui uma excelente API que pode ser utilizada para criar sistemas de build bem flexíveis e robustos.&#10;</description><content:encoded>&lt;p&gt;A Unity possui um sistema de build onde você pode exportar seu projeto para diferentes plataformas e otimizaçoes. Este sistema é um pouco limitado quando utilizado através da interface do Editor, porém ele possui uma excelente API que pode ser utilizada para criar sistemas de build bem flexíveis e robustos.&lt;/p&gt;&#10;&lt;p&gt;Neste vídeo eu demonstro como utilizar a API BuildPipeline da Unity e como gerar uma build através da linha de comando sem precisar abrir o projeto - o que pode ser utilizado em conjunto com sistemas de integraçao contínua, como o Jenkins. Apesar de não mostrar detalhes de como configurar, ao final do vídeo mostro como o Jenkins pode ser utilizado para gerar a build do exemplo do vídeo.&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/oiAWZxeOzmA" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;Alguns links mencionados no vídeo:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;a href="https://docs.unity3d.com/ScriptReference/BuildPipeline.html" target="_blank" rel="noreferrer"&gt;Unity BuildPipeline&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://docs.unity3d.com/Manual/EditorCommandLineArguments.html" target="_blank" rel="noreferrer"&gt;Unity Editor command line arguments&lt;/a&gt;&lt;/li&gt;&#10;&lt;li&gt;&lt;a href="https://gamedeveloper.com.br/raspberry-pi-zero-w-jenkins/" &gt;Rodando Jenkins em um Raspberry Pi Zero W&lt;/a&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Abaixo está a linha de comando executada para gerar as builds no vídeo. Os caminhos nesta linha de comando são do meu computador e podem não funcionar no seu, modifique de acordo com o seu ambiente de desenvolvimento.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;#34;C:\Program Files\Unity\Hub\Editor\2020.3.23f1\Editor\Unity.exe&amp;#34; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -quit \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -batchmode \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -projectPath &amp;#34;C:\Projects\unity-build-system-sample&amp;#34; \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -executeMethod BuildSystem.BuildAll \&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -logFile &amp;#34;C:\Projects\unity-build-system-sample\BuildLog.txt&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;O projeto do vídeo está &lt;a href="https://github.com/cicanci/unity-build-system-sample" target="_blank" rel="noreferrer"&gt;disponível neste repositório no meu GitHub&lt;/a&gt;. Dúvidas, comentários ou sugestões para futuros vídeos deixem aqui no post ou lá no vídeo no YouTube.&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/images/2021/12/sistema-build-unity.webp" medium="image"/></item><item><title>Como fazer um plugin para Android em Java na Unity</title><link>https://gamedeveloper.com.br/unity-plugin-android/</link><guid>https://gamedeveloper.com.br/unity-plugin-android/</guid><pubDate>Mon, 01 Mar 2021 00:00:00 +0000</pubDate><category>Unity</category><description>Existem algumas estruturas possíveis para implementar um plugin Android na Unity. Quando utilizamos um plugin desenvolvido por terceiros é comum que a sua distribuição seja através de um arquivo AAR, que é uma biblioteca java para Android, junto com alguns scripts em C# para sua utilização. Esta é a opção mais simples, pois a Unity já reconhece o arquivo AAR como uma biblioteca Android e cuida do resto na compilação. Também é possível utilizar um arquivo JAR, mas não é um formato muito utilizado hoje em dia para desenvolvimento com Android, e até exige um pouco mais de configuração para ser utilizado na Unity.&#10;</description><content:encoded>&lt;p&gt;Existem algumas estruturas possíveis para implementar um plugin Android na Unity. Quando utilizamos um plugin desenvolvido por terceiros é comum que a sua distribuição seja através de um &lt;a href="https://developer.android.com/studio/projects/android-library.html#aar-contents" target="_blank" rel="noreferrer"&gt;arquivo AAR&lt;/a&gt;, que é uma biblioteca java para Android, junto com alguns scripts em C# para sua utilização. Esta é a opção mais simples, pois a Unity já reconhece o arquivo AAR como uma biblioteca Android e cuida do resto na compilação. Também é possível utilizar um &lt;a href="https://docs.oracle.com/javase/tutorial/deployment/jar/basicsindex.html" target="_blank" rel="noreferrer"&gt;arquivo JAR&lt;/a&gt;, mas não é um formato muito utilizado hoje em dia para desenvolvimento com Android, e até exige um pouco mais de configuração para ser utilizado na Unity.&lt;/p&gt;&#10;&lt;p&gt;Outra maneira de desenvolver um plugin dentro da Unity é mantendo o código java dentro do próprio projeto e, com ajuda de alguns outros arquivos, a Unity consegue configurar e compilar seu código Java como uma biblioteca para Android. Neste post não vou explicar como criar um arquivo AAR, mas é tão simples quanto criar um &lt;a href="https://developer.android.com/studio/projects/android-library" target="_blank" rel="noreferrer"&gt;projeto de library no Android Studio&lt;/a&gt; e compilar para exportar o AAR, e a partir daí pode pular para a integração em C# na Unity.&lt;/p&gt;&#10;&#10;&lt;h4 class="relative group"&gt;Estrutura&#10; &lt;div id="estrutura" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#estrutura" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h4&gt;&#10;&lt;p&gt;Para usar o código java dentro da Unity precisamos montar a estrutura abaixo, assim a engine vai compilar o código corretamente como uma biblioteca Android. Qualquer plugin com código nativo deve sempre ser colocado dentro de uma pasta &lt;em&gt;Plugins&lt;/em&gt;, e em uma sub-pasta com o nome da plataforma, no caso &lt;em&gt;Android&lt;/em&gt;. Na pasta Android é onde fica a biblioteca Android, onde no exemplo abaixo é chamada &lt;strong&gt;native-test-lib&lt;/strong&gt;. Agora precisamos de pelo menos mais 3 arquivos, que eu irei descrever em seguida.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├───Plugins&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └───Android&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └───native-test-lib&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ AndroidManifest.xml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ build.gradle&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │ project.properties&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └───src&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └───com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └───cicanci&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ │&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ └───unity&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;│ NativeTest.java&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&#10;&lt;h4 class="relative group"&gt;Arquivo de configuração&#10; &lt;div id="arquivo-de-configuração" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#arquivo-de-configura%c3%a7%c3%a3o" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h4&gt;&#10;&lt;p&gt;No arquivo &lt;code&gt;project.properties&lt;/code&gt; é necessário colocar apenas dois parâmetros para que o projeto seja reconhecido como uma biblioteca Android, a versão da &lt;a href="https://developer.android.com/studio/releases/platforms" target="_blank" rel="noreferrer"&gt;API do Android&lt;/a&gt; que será a target (não é a versão mínima e não necessariamente a versão que será utilizada na compilação), e o parâmetro que habilita o projeto como &lt;em&gt;library&lt;/em&gt;.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;target=android-21&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;android.library=true&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&#10;&lt;h4 class="relative group"&gt;Android Manifest&#10; &lt;div id="android-manifest" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#android-manifest" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h4&gt;&#10;&lt;p&gt;O &lt;code&gt;AndroidManifest.xml&lt;/code&gt; utilizado na library tem a o mínimo necessário para a &lt;a href="https://developer.android.com/studio/releases/platforms" target="_blank" rel="noreferrer"&gt;definição deste arquivo&lt;/a&gt;: &lt;em&gt;package&lt;/em&gt; e versão. O package é o mesmo que será utilizado no arquivo Java, e neste exemplo é &lt;em&gt;com.cicanci.unity&lt;/em&gt;.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34; encoding=&amp;#34;utf-8&amp;#34;?&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;manifest xmlns:android=&amp;#34;http://schemas.android.com/apk/res/android&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; package=&amp;#34;com.cicanci.unity&amp;#34; android:versionCode=&amp;#34;1&amp;#34; android:versionName=&amp;#34;1.0&amp;#34; &amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &amp;lt;application&amp;gt;&amp;lt;/application&amp;gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&amp;lt;/manifest&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&#10;&lt;h4 class="relative group"&gt;Compilação com gradle&#10; &lt;div id="compilação-com-gradle" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#compila%c3%a7%c3%a3o-com-gradle" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h4&gt;&#10;&lt;p&gt;Por fim, precisaremos apenas do arquivo &lt;code&gt;build.gradle&lt;/code&gt; que também define o projeto como library e mostra para o compilador onde está o &lt;code&gt;AndroidManifest.xml&lt;/code&gt; e o código Java (na pasta &lt;code&gt;src&lt;/code&gt;). Aqui também temos definidas algumas versões para o SDK do Android utilizado para compilação e o mesmo target definido no arquivo &lt;code&gt;project.properties&lt;/code&gt;. Este arquivo será compilado pela Unity junto com o &lt;a href="https://gradle.org/" target="_blank" rel="noreferrer"&gt;gradle&lt;/a&gt; do projeto.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;apply plugin: &amp;#39;android-library&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;android {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; sourceSets {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; main {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; manifest.srcFile &amp;#39;AndroidManifest.xml&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; java.srcDirs = [&amp;#39;src&amp;#39;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; compileSdkVersion 30&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; buildToolsVersion &amp;#39;30.0.3&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; defaultConfig {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; targetSdkVersion 21&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Com todos os arquivos acima definidos e utilizando a estrutura mostrada no início do post, a Unity irá reconhecer o projeto como um plugin para Android, como podemos ver na imagem abaixo.&lt;/p&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2021/03/unity-android-plugin.webp"&gt;&#10;&lt;/figure&gt;&#10;&#10;&lt;h4 class="relative group"&gt;Código java&#10; &lt;div id="código-java" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#c%c3%b3digo-java" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h4&gt;&#10;&lt;p&gt;Eu quis manter este exemplo bem simples por que meu objetivo é demonstrar como criar um plugin e utilizá-lo na Unity, por isso o código abaixo faz algo bem simples: recebe e retorna strings e inteiros. O package aqui deve ser o mesmo definido no &lt;code&gt;AndroidManifest.xml&lt;/code&gt;. Este é um exemplo simples, porém não existem limites para uma library Android aqui quando comparada com um aplicativo para Android feito fora da Unity.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-java" data-lang="java"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;com.cicanci.unity&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NativeTest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;private&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Hello from Android&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getCounter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;setCounter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;counter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;A localização do arquivo Java dentro do plugin deve ter ser em uma estrutura de pastas que reflitam o package. Como neste exemplo o package é &lt;code&gt;com.cicanci.unity&lt;/code&gt;, o arquivo &lt;code&gt;NativeTest.java&lt;/code&gt; deve ficar dentro de &lt;code&gt;Plugins/Android/native-test-lib/src/com/cicanci/unity/&lt;/code&gt; - a localização do plugin Android na Unity + a pasta que o arquivo &lt;code&gt;build.gradle&lt;/code&gt; vai procurar o código Java que é &lt;code&gt;src&lt;/code&gt; + estrutura que reflete o package no &lt;code&gt;AndroidManifest.xml&lt;/code&gt;.&lt;/p&gt;&#10;&#10;&lt;h4 class="relative group"&gt;Implementação no C#&#10; &lt;div id="implementação-no-c" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#implementa%c3%a7%c3%a3o-no-c" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h4&gt;&#10;&lt;p&gt;A parte final do plugin é sua utilização na Unity através do C#, e nisso a engine ajuda bastante com a classe &lt;code&gt;AndroidJavaObject&lt;/code&gt;. Com esta class iremos criar nosso objeto com o nome completo da classe (package + nome da classe). Após criar o objeto podemos executar métodos da classe Java utilizando o método &lt;code&gt;Call()&lt;/code&gt;, que também possui parâmetro para retornar um tipo quando o método Java não é &lt;em&gt;void&lt;/em&gt;.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#if&lt;/span&gt; &lt;span class="n"&gt;UNITY_ANDROID&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NativeTestAndroid&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;AndroidJavaObject&lt;/span&gt; &lt;span class="n"&gt;_nativeTestClass&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;NativeTestAndroid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_nativeTestClass&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;AndroidJavaObject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;com.cicanci.unity.NativeTest&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;GetCounter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_nativeTestClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Call&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;getCounter&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;GetMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_nativeTestClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Call&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;getMessage&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;SetCounter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_nativeTestClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;setCounter&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;SetMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_nativeTestClass&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;setMessage&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#endif&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Não existe muito segredo, é realmente bem simples executar um código de uma library Android em Java no C# da Unity. Basta prestar atenção no tipo do retorno do método e no seu nome na hora de definir os métodos no C#. Outra dica é colocar seu código C# dentro de um &lt;code&gt;#if UNITY_ANDROID&lt;/code&gt; para evitar erros de compilação em outras plataformas já que a classe &lt;code&gt;AndroidJavaObject&lt;/code&gt; existe apenas quando a plataforma é Android na Unity.&lt;/p&gt;&#10;&#10;&lt;h4 class="relative group"&gt;Conclusão&#10; &lt;div id="conclusão" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#conclus%c3%a3o" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h4&gt;&#10;&lt;p&gt;Neste post quis mostrar como é criar um plugin para Android na Unity e, a partir deste template é possível fazer muitas coisas. Na época da Unity 5 era mais comum criar plugins para Android, já que a engine tinha um suporte bem limitado para esta plataforma, isso mudou bastante nas versões posteriores. Hoje muito do que você precisa já tem suporte para Android na Unity, porém pode ser que seja limitado ou que você queira ter controle sobre o código - nestes casos é bom fazer seu próprio plugin.&lt;/p&gt;&#10;&lt;p&gt;Quando preciso desenvolver um plugin para Android na Unity eu geralmente crio um projeto novo no Android Studio e faço tudo por lá, inclusive com um aplicativo de testes. Desta forma é possível utilizar todas as ferramentas de desenvolvimento presentes na IDE antes de ir para a Unity, onde seria mais difícil e nada prático desenvolver uma library Android mais complexa. Eu prefiro exportar o projeto como um arquivo AAR, porém para algo simples e pequeno eu acabo deixando o código dentro da Unity e evito manter um projeto Android apenas para esta finalidade.&lt;/p&gt;&#10;&lt;p&gt;Todo o código deste post e um exemplo de uso está disponível neste &lt;a href="https://github.com/cicanci/unity-mobile-plugin-sample/tree/v1.0.0" target="_blank" rel="noreferrer"&gt;repositório no GitHub&lt;/a&gt;. Pretendo escrever outro post mostrando como fazer o mesmo plugin para iOS e sua utilização na Unity.&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/images/2021/03/unity-android-sample-plugin.webp" medium="image"/></item><item><title>Relatório da Unity sobre jogos e tendências</title><link>https://gamedeveloper.com.br/unity-gaming-report-2021/</link><guid>https://gamedeveloper.com.br/unity-gaming-report-2021/</guid><pubDate>Thu, 25 Feb 2021 00:00:00 +0000</pubDate><category>Unity</category><description>A Unity publicou esta semana o 2021 Game Report contendo informações e muitos dados sobre a indústria de jogos em 2020, apontando tendências para 2021. Os dados analisados no relatório são de desenvolvedores que utilizam a engine e, apesar de representar apenas quem publicou jogos utilizando a Unity, ainda assim é bem relevante como mostram os dados.&#10;</description><content:encoded>&lt;p&gt;A &lt;a href="https://unity3d.com" target="_blank" rel="noreferrer"&gt;Unity&lt;/a&gt; publicou esta semana o &lt;a href="https://create.unity3d.com/2021-game-report" target="_blank" rel="noreferrer"&gt;2021 Game Report&lt;/a&gt; contendo informações e muitos dados sobre a indústria de jogos em 2020, apontando tendências para 2021. Os dados analisados no relatório são de desenvolvedores que utilizam a &lt;em&gt;engine&lt;/em&gt; e, apesar de representar apenas quem publicou jogos utilizando a Unity, ainda assim é bem relevante como mostram os dados.&lt;/p&gt;&#10;&lt;p&gt;Os números impressionantes demonstram um crescimento da engine e da indústria de jogos. De acordo com a Unity, jogos desenvolvidos com a engine foram baixados cerca de &lt;strong&gt;5 bilhões&lt;/strong&gt; de vezes por mês em 2020, sendo que o número de jogadores ativos mensal foi em média &lt;strong&gt;2.8 bilhões&lt;/strong&gt;. A rede de publicidade &lt;a href="https://unity.com/solutions/unity-ads" target="_blank" rel="noreferrer"&gt;Unity Ads&lt;/a&gt; teve &lt;strong&gt;23 bilhões&lt;/strong&gt; de impressões de anúncios por mês.&lt;/p&gt;&#10;&lt;p&gt;O relatório também mostra que a pandemia do &lt;em&gt;COVID-19&lt;/em&gt; contribuiu para o aumento da quantidade de jogadores que buscaram jogos &lt;em&gt;mid/hardcore&lt;/em&gt; ao invés de casuais, que eram mais populares principalmente por quem utilizava com frequencia o transporte público. O gráfico abaixo faz um comparativo entre 2019 e 2020 e mostra que os jogadores estão dando preferência por jogos com mais contéudo já que possuem mais tempo disponível sem interrupções para jogar.&lt;/p&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2021/02/mobile-covid.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;p&gt;O &lt;em&gt;revenue&lt;/em&gt;, que é a receita que o jogo faz, também cresceu em comparação com o ano anterior. O gráfico abaixo mostra que no D1, ou seja, no dia seguinte após a primeira vez que o jogo foi aberto (D0), a receita gerada por compras dentro do jogo (IAP) aumentou bastante. Este aumento de revenue também foi bem expressivo em jogos que possuem ads (publicidade) como fonte de receita.&lt;/p&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2021/02/revenue-covid.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;p&gt;Estes dados e muito mais estão disponíveis gratuitamente no relatório da Unity, &lt;a href="https://create.unity3d.com/2021-game-report" target="_blank" rel="noreferrer"&gt;disponível aqui&lt;/a&gt; em Inglês. Recomendo a leitura e análise dos dados, principalmente se você tem algum projeto em desenvolvimento para ser lançado em breve - muitos dados ainda são válidos e podem ser considerados indicadores para um produto.&lt;/p&gt;&#10;&lt;p&gt;Por fim, a Unity fez algumas previsões baseadas nas tendências observadas durante 2020:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Mudanças em privacidade terão um grande impacto em jogos mobile (exemplo disso é o &lt;a href="https://developer.apple.com/app-store/user-privacy-and-data-use/" target="_blank" rel="noreferrer"&gt;AppTrackingTransparency da Apple&lt;/a&gt; que vai ser habilitado em breve no iOS 14.5).&lt;/li&gt;&#10;&lt;li&gt;&lt;em&gt;Cross-platform&lt;/em&gt; entre mobile e HD (desktop/consoles) é o futuro.&lt;/li&gt;&#10;&lt;li&gt;Mesmo após o COVID-19 o número de jogadores vai continuar alto.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Eu pessoalmente concordo e acredito nas previsões da Unity, principalmente na questão do cross-platform entre mobile e desktop/consoles. Além disso, acredito que a geração anterior de consoles, PS4 e Xbox One, vão continuar com novos lançamentos por um tempo maior do que na geração do PS3 e Xbox 360. A base de jogadores é bem grande e acho que vai demorar para a maioria migrar para a geração atual do PS5 e Xbox Series X/S. E você, leitor, tem alguma outra previsão para a indústria de jogos em 2021?&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/images/2021/02/unity-report-2021.webp" medium="image"/></item><item><title>Exemplo do Design Pattern Command na Unity com C#</title><link>https://gamedeveloper.com.br/design-pattern-command/</link><guid>https://gamedeveloper.com.br/design-pattern-command/</guid><pubDate>Tue, 29 Dec 2020 00:00:00 +0000</pubDate><category>Unity</category><description>Sempre recomendo o livro Game Programming Patterns, que possui versões física e digital à venda, além de uma online gratuita disponibilizada pelo autor, Robert Nystrom. Este livro revisita os design patterns definidos na década de 1990 pela "Gangue dos Quatro", focando no seu uso para o desenvolvimento de jogos.&#10;</description><content:encoded>&lt;p&gt;Sempre recomendo o livro &lt;a href="https://gameprogrammingpatterns.com" target="_blank" rel="noreferrer"&gt;Game Programming Patterns&lt;/a&gt;, que possui versões física e digital à venda, além de uma &lt;a href="https://gameprogrammingpatterns.com/contents.html" target="_blank" rel="noreferrer"&gt;online gratuita&lt;/a&gt; disponibilizada pelo autor, &lt;a href="https://twitter.com/munificentbob" target="_blank" rel="noreferrer"&gt;Robert Nystrom&lt;/a&gt;. Este livro revisita os &lt;a href="https://en.wikipedia.org/wiki/Design_Patterns" target="_blank" rel="noreferrer"&gt;design patterns&lt;/a&gt; definidos na década de 1990 pela &amp;quot;Gangue dos Quatro&amp;quot;, focando no seu uso para o desenvolvimento de jogos.&lt;/p&gt;&#10;&lt;p&gt;O livro conta com excelentes exemplos e com pseudocódigo baseado em C/C++, além de descreve situações em que cada programming pattern pode ser utilizado. Já realizei algumas palestras sobre este assunto e utilizei este livro como base, sendo a mais recente na &lt;a href="https://gamedeveloper.com.br/palestra-tdc-porto-alegre-2019/" &gt;TDC Porto Alegre 2019&lt;/a&gt;. Meu objetivo com este post e, com os próximos que virão, é criar exemplos do uso de cada programming pattern na game engine Unity e com a linguagem de programação C#.&lt;/p&gt;&#10;&lt;p&gt;Seguindo a ordem do livro, este primeiro post será sobre o &lt;a href="https://gameprogrammingpatterns.com/command.html" target="_blank" rel="noreferrer"&gt;Design Pattern Command&lt;/a&gt;. O código deste exemplo, assim como de todos os próximos, pode ser acessado neste &lt;a href="https://github.com/cicanci/game-programming-patterns" target="_blank" rel="noreferrer"&gt;repositório do GitHub&lt;/a&gt;.&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;Design Pattern Command&#10; &lt;div id="design-pattern-command" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#design-pattern-command" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;O Command é um design pattern que tem como objetivo encapsular um método ou ação. Em uma definição muito simples pode-se dizer que é um padrão para &lt;em&gt;callbacks&lt;/em&gt;. Um exemplo bem prático do Command é o input de um jogo. Imagine que seu jogo possui uma opção para que o jogador modifique as ações de cada botão, seja por preferencia pessoal ou acessibilidade. Com a Implementação do Command fica simples modificar o comando que um botão executa, como demonstrado no exemplo a seguir.&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;Implementação na Unity com C#&#10; &lt;div id="implementação-na-unity-com-c" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#implementa%c3%a7%c3%a3o-na-unity-com-c" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;Neste exemplo de implementação existem duas ações possíveis para o jogador: Pular e Atirar. Para simplificar o exemplo, cada ação será apenas uma mensagem de log. O código abaixo define exatamente isso, dois comandos que podem ser executados. É importante ter uma interface neste caso, ou pelo menos uma classe base, para que o código que executar estas ações não precise necessariamente saber o tipo de cada classe derivada.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;ICommand&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;JumpCommand&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ICommand&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Execute command: Jump&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FireCommand&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ICommand&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Execute command: Fire&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;E é basicamente isso, uma interface com o método que executará uma ação e duas implementações desta interface. Agora ambas ações podem ser utilizadas em outra classe, como será demonstrado no &lt;em&gt;MonoBehaviour&lt;/em&gt; abaixo. A classe abaixo possui dois métodos públicos executados por botões na Unity, o &lt;code&gt;ButtonA()&lt;/code&gt; e o &lt;code&gt;ButtonB()&lt;/code&gt;. Estes métodos executam qualquer comando associado com as respectivas variáveis, as quais possuem o tipo da interface &lt;code&gt;ICommand&lt;/code&gt;.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DesignPatternCommand&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;ICommand&lt;/span&gt; &lt;span class="n"&gt;_buttonA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;ICommand&lt;/span&gt; &lt;span class="n"&gt;_buttonB&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_buttonA&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;JumpCommand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_buttonB&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;FireCommand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;ButtonA&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_buttonA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;ButtonB&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_buttonB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Quando executado, o código acima irá atribuir a ação de pular para o botão A e a ação de atirar para o botão B. Agora imagine que, neste exemplo, teremos uma opção que permite o jogador inverter os comandos dos botões. Para isso, um método como este abaixo irá alterar o comando dos botões sem a necessidade de qualquer outra modificação no código.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;ChangeButtons&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_buttonA&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;FireCommand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_buttonB&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;JumpCommand&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Este é um exemplo bem simples para explicar o conceito por trás deste programming pattern. A partir disso pode-se ver como o Command é um poderoso recurso para todo programador, pois permite alterar ações sem criar dependências no código. Existem outros exemplos interessantes para o seu uso, como um sistema de avançar e voltar no tempo onde todas as ações do jogador podem ser uma lista de comandos executados. Isso pode ser utilizado até mesmo em um editor para desfazer e refazer uma determinada ação.&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;Exemplo&#10; &lt;div id="exemplo" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#exemplo" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;Neste &lt;a href="https://github.com/cicanci/game-programming-patterns" target="_blank" rel="noreferrer"&gt;repositório do GitHub&lt;/a&gt; existe um exemplo utilizando o código acima, porém com 4 botões de ações do jogador e um outro botão que permite embaralhar as ações.&lt;/p&gt;&#10;&lt;p&gt;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2020/12/design-pattern-command.webp"&gt;&#10;&lt;/figure&gt;&#10;&#10;O Command é um padrão simples, mas que é muito poderoso quando entendido e utilizado corretamente na arquitetura de um jogo. Imagine ter que adicionar novos botões no exemplo acima, ou um hardware diferente para o input. Tudo isso pode ser feito de forma prática com o Command. Este programming pattern é um bom aliado para tornar um jogo mais acessível, permitindo a customização do controle do jogo pelo jogador.&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/categories/unity.webp" medium="image"/></item><item><title>Boas práticas para uso de logs na Unity</title><link>https://gamedeveloper.com.br/unity-debug-log/</link><guid>https://gamedeveloper.com.br/unity-debug-log/</guid><pubDate>Mon, 26 Oct 2020 00:00:00 +0000</pubDate><category>Unity</category><description>Neste post quero compartilhar algumas dicas e boas práticas para uso do Debug.Log() na Unity. Pode parecer intuitivo utilizar a API da Unity para registrar todo tipo de ação que o jogador fizer, mas existem algumas maneiras de fazer isso que podem tornar o processo de debug e teste mais fácil, além de registrar logs apenas do que realmente é necessário.&#10;</description><content:encoded>&lt;p&gt;Neste post quero compartilhar algumas dicas e boas práticas para uso do &lt;code&gt;Debug.Log()&lt;/code&gt; na Unity. Pode parecer intuitivo utilizar a API da Unity para registrar todo tipo de ação que o jogador fizer, mas existem algumas maneiras de fazer isso que podem tornar o processo de debug e teste mais fácil, além de registrar logs apenas do que realmente é necessário.&lt;/p&gt;&#10;&lt;p&gt;Em um jogo publicado não faz sentido ter chamadas para o &lt;code&gt;Debug.Log()&lt;/code&gt;, pois que utilidade existe em registar uma mensagem do tipo &lt;code&gt;&amp;quot;Item found!&amp;quot;&lt;/code&gt; se isso não é relevante para o jogador e você não poderá ver esta mensagem no aparelho dele? O uso do &lt;code&gt;Debug.Log()&lt;/code&gt; pode ser muito útil enquanto está desenvolvendo e testando um jogo. Mas, mesmo assim, as mensagens precisam ser úteis e ter um contexto que ajude a entender o que está acontecendo.&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;Mensagens relevantes&#10; &lt;div id="mensagens-relevantes" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#mensagens-relevantes" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;Vamos analisar a seguinte sequencia de mensagens:&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Button pressed!&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Button pressed!&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Player killed monster&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Monster drops: 2&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Apesar de ser possível entender o que aconteceu, estas mensagens são bem pobres em informações. Nas mensagens acima não é possível saber qual botão foi pressionado, qual monstro foi derrotado, e qual item o monstro largou. Perceba que nem é possível ver se o jogador pegou o item a partir destes logs, e se algum erro acontecer será bem difícil de reproduzir e corrigir. Por isso, é importante registrar mensagens relevantes e com contexto suficiente para entender o que aconteceu. Vamos analisar agora a mesma sequencia, porém com mais detalhes:&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;State changed: EXPLORING -&amp;gt; START_BATTLE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Player attacked monster blue and caused 10 damage (critical). Monster blue has 5HP&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Player attacked monster blue and caused 7 damage. Monster blue has 0HP&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Monster blue was defeated. Drops: {&amp;#34;potion&amp;#34;: &amp;#34;potion_red&amp;#34;,&amp;#34;gold&amp;#34;: 10}. Experience: +2XP&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;State changed: START_BATTLE -&amp;gt; END_BATTLE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Player picked up items: {&amp;#34;potion&amp;#34;: &amp;#34;potion_red&amp;#34;,&amp;#34;gold&amp;#34;: 10}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Player received 2XP. Now has 32/50&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;State changed: END_BATTLE -&amp;gt; EXPLORING&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Ao invés de registrar um botão foi pressionado, é registrada a ação desencadeada pelo botão, o ataque e qual a consequência da ação, que foi causar dano no monstro blue. Na mesma linha do log é possível ver quanto dano foi causado, se foi um ataque crítico e quanta vida resta para o monstro. Após ser derrotado, é possível ver quais itens o monstro derrubou e quanta experiência deu ao jogador.&lt;/p&gt;&#10;&lt;p&gt;Podemos ver também que o jogador pegou os itens, recebeu a experiência, quanta experiência tem no momento (32), e quanto precisará para o próximo nível (50). Um detalhe a mais são os registros de mudança de estado: a batalha inicia e tem um fim. Assim, fica fácil ver que todas aquelas ações aconteceram em uma batalha, o que torna mais simples de entender e reproduzir um determinado comportamento para corrigir um erro ou até ajustar o balanceamento do jogo.&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;Mensagens seletivas&#10; &lt;div id="mensagens-seletivas" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#mensagens-seletivas" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;Apesar das mensagens acima terem contexto e serem relevantes, ainda assim, podem criar uma quantidade desnecessária de logs em uma sessão de jogo. Em alguns momentos vamos querer ver os logs da batalha em detalhes, porém em outros, vamos querer ver apenas os logs de mudança de estados. E em outros nenhum log, apenas erros (quando acontecerem).&lt;/p&gt;&#10;&lt;p&gt;Uma das maneiras de escolher quais logs devem ser exibidos no jogo é utilizar &lt;code&gt;Scripting Define Symbols&lt;/code&gt; no código e habilitá-los no Player Settings da Unity para a plataforma desejada. Assim, é possível habilitar determinados logs para determinadas situações. Uma solução bem prática é criar uma classe estática responsável por chamar a API de logs da Unity, e fazer o jogo utilizá-la ao invés de chamar &lt;code&gt;Debug.Log()&lt;/code&gt; diretamente.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [System.Diagnostics.Conditional(&amp;#34;ENABLE_LOG_BATTLE&amp;#34;)]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;LogBattle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [System.Diagnostics.Conditional(&amp;#34;ENABLE_LOG_STATE&amp;#34;)]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;LogChangeState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;LogWarn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LogWarning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Os métodos &lt;code&gt;LogBattle()&lt;/code&gt; e &lt;code&gt;LogChangeState()&lt;/code&gt; possuem o atributo &lt;em&gt;Conditional&lt;/em&gt; com os define symbols &lt;code&gt;&amp;quot;ENABLE_LOG_BATTLE&amp;quot;&lt;/code&gt; e &lt;code&gt;&amp;quot;ENABLE_LOG_STATE&amp;quot;&lt;/code&gt;, respectivamente. Desta maneira, é possível chamar ambos os métodos a qualquer momento no jogo, mas eles só serão executados se os respectivos define symbols estiverem habilitados no Player Settings, conforme imagem abaixo. Adicionei também métodos para &lt;em&gt;Warnings&lt;/em&gt; e &lt;em&gt;Errors&lt;/em&gt;, assim todos os logs podem ser concentrados nesta classe. Outra vantagem de centralizar tudo em uma classe é poder customizar as mensagens adicionando qualquer tipo de informação ou formatação.&lt;/p&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2020/10/unity-player-settings.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;p&gt;Vale lembrar que os define symbols são &lt;em&gt;por plataforma&lt;/em&gt;, ou seja, é necessário defini-los para cada plataforma que será utilizada. Uma maneira bem prática de adicionar e remover os define symbols é criando um script que faça isso. Este script pode ser usado a partir de um menu, ou até em um sistema de build. Isso é muito útil para gerar builds em um CI como o Jenkins, por exemplo, parametrizando a build para ter ou não determinados logs.&lt;/p&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2020/10/unity-player-settings-platforms.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;p&gt;Utilizar uma classe como a Logger causa um efeito colateral e pode ser visto no Editor: ao clicar duas vezes em uma mensagem de log será aberto o script do Logger ao invés do script que executou o método, como acontece quando usamos diretamente o &lt;code&gt;Debug.Log()&lt;/code&gt;. Isto pode ser corrigido modificando o código e adicionando um &lt;code&gt;delegate&lt;/code&gt;.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Logger&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;delegate&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;LogHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cp"&gt;#if&lt;/span&gt; &lt;span class="n"&gt;ENABLE_LOG_BATTLE&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;LogHandler&lt;/span&gt; &lt;span class="n"&gt;LogBattle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cp"&gt;#else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;LogHandler&lt;/span&gt; &lt;span class="n"&gt;LogBattle&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cp"&gt;#endif&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cp"&gt;#if&lt;/span&gt; &lt;span class="n"&gt;ENABLE_LOG_STATE&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;LogHandler&lt;/span&gt; &lt;span class="n"&gt;LogChangeState&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cp"&gt;#else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;LogHandler&lt;/span&gt; &lt;span class="n"&gt;LogChangeState&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="cp"&gt;#endif&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;LogHandler&lt;/span&gt; &lt;span class="n"&gt;LogWarn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LogWarning&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;LogHandler&lt;/span&gt; &lt;span class="n"&gt;LogError&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;O código fica um pouco mais complexo, porém agora ao clicar duas vezes em uma mensagem de log no Editor o script que executou o Logger será aberto. Infelizmente, não é possível utilizar o atributo &lt;em&gt;Conditional&lt;/em&gt;, pois estamos usando uma propriedade ao invés de um método, por isso é necessário utilizar o &lt;code&gt;#if ... #else ... #endif&lt;/code&gt;. Quando o define symbol não estiver no Player Settings, nada acontece.&lt;/p&gt;&#10;&lt;p&gt;Existem outras coisas que podemos fazer para melhorar os logs em um jogo, desde cores e formatação até um sistema mais robusto para ligar e desligar mensagens em determinado tipo de build. Meu objetivo neste post foi mostrar algumas coisas que considero boas práticas e muito úteis para um projeto. Logs são muito importantes para um jogo, e devem ser tratados como tal. Gaste um minuto a mais para escrever uma mensagem útil, com informações que vão realmente te ajudar a entender o que está acontecendo.&lt;/p&gt;&#10;&lt;p&gt;Minha sugestão de centralizar os logs em uma classe e combinar com define symbols ajudam, porém muitas mensagens podem poluir e esconder informações úteis e até causar problemas de performance no jogo sem perceber. Seja bem crítico para não deixar seu projeto se tornar um mar de mensagens inúteis e planeje um tempo para revisar as mensagens de tempos em tempos.&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/categories/unity.webp" medium="image"/></item><item><title>Compressão de Asset Bundles na Unity</title><link>https://gamedeveloper.com.br/unity-asset-bundle-compression/</link><guid>https://gamedeveloper.com.br/unity-asset-bundle-compression/</guid><pubDate>Mon, 24 Aug 2020 00:00:00 +0000</pubDate><category>Unity</category><description>A utilização de Asset Bundles na Unity é uma boa solução da própria engine para download de recursos. É comum utilizar esta forma de distribuição de assets para poder atualizar ou adicionar conteúdo ao jogo após o lançamento, não sendo necessário publicar um novo binário do jogo. Desta forma, jogos podem adicionar personagens, níveis, ou fazer correções em modelos e imagens sem precisar de uma versão nova do jogo. A única limitação é não poder adicionar novos scripts ou utilizar scripts em versões diferentes dos que estão no binário, o que faz os desenvolvedores pensarem em formas de tornar seus jogos mais flexíveis e extrair o máximo dos asset bundles.&#10;</description><content:encoded>&lt;p&gt;A utilização de &lt;a href="https://docs.unity3d.com/Manual/AssetBundlesIntro.html" target="_blank" rel="noreferrer"&gt;Asset Bundles na Unity&lt;/a&gt; é uma boa solução da própria engine para download de recursos. É comum utilizar esta forma de distribuição de assets para poder atualizar ou adicionar conteúdo ao jogo após o lançamento, não sendo necessário publicar um novo binário do jogo. Desta forma, jogos podem adicionar personagens, níveis, ou fazer correções em modelos e imagens sem precisar de uma versão nova do jogo. A única limitação é não poder adicionar novos scripts ou utilizar scripts em versões diferentes dos que estão no binário, o que faz os desenvolvedores pensarem em formas de tornar seus jogos mais flexíveis e extrair o máximo dos asset bundles.&lt;/p&gt;&#10;&lt;p&gt;Porém, existem mais vantagens em utilizar asset bundles do que apenas atualizar o conteúdo do jogo: é possível reduzir o tamanho do jogo, o uso de memória, uso de CPU e até tempo de loading ajustando algumas opções de compressão na Unity. O objetivo deste post é explorar algumas combinações de compressão, utilizando a plataforma Android como exemplo, e comparar os resultados. Se você quiser saber mais sobre asset bundles, recomendo este &lt;a href="https://learn.unity.com/tutorial/assets-resources-and-assetbundles" target="_blank" rel="noreferrer"&gt;curso gratuito da Unity&lt;/a&gt;.&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;Configuração&#10; &lt;div id="configuração" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#configura%c3%a7%c3%a3o" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;Escolhi a plataforma Android para o teste por ser mais simples de compilar e testar em um aparelho. Utilizei um Samsung Galaxy S9 com Android 8.0.0 nos testes e instalei um total de 27 builds nele, cada uma contendo uma combinação de compressão no APK e nos asset bundles. Para deixar o teste mais simples, todos asset bundles foram carregados a partir da pasta StreamingAssets. A versão da Unity utilizada foi a &lt;a href="https://unity3d.com/unity/whats-new/2019.4.7" target="_blank" rel="noreferrer"&gt;2019.4.7f1&lt;/a&gt; e todas as builds foram geradas em modo release.&lt;/p&gt;&#10;&lt;p&gt;A primeira variação foi a configuração do APK gerado pela Unity no &lt;strong&gt;Player Settings&lt;/strong&gt;. Realizei testes com o &lt;strong&gt;Scripting Backend&lt;/strong&gt; Mono e IL2CPP, além de testar com as arquiteturas ARMv7 e AMR64, já que o aparelho utilizado no teste suporta ambas.&lt;/p&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2020/08/player-settings.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;p&gt;No &lt;strong&gt;Build Settings&lt;/strong&gt; testei os &lt;a href="https://docs.unity3d.com/Manual/android-BuildProcess.html" target="_blank" rel="noreferrer"&gt;métodos de compressão&lt;/a&gt; do APK: Default (ZIP), LZ4 (recomendado para &lt;strong&gt;development&lt;/strong&gt;) e LZ4HC (melhor compressão, porém processo de build mais lento). Esta configuração, assim como as anteriores, não afetam os asset bundles, porém são algumas mudanças no APK que quis testar para ver a influência na build.&lt;/p&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2020/08/build-settings.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;p&gt;As últimas configurações foram feitas na geração dos asset bundles, utilizando o Unity package &lt;a href="https://docs.unity3d.com/Packages/com.unity.assetbundlebrowser@1.7/manual/index.html" target="_blank" rel="noreferrer"&gt;Asset Bundle Browser&lt;/a&gt; versão 1.0.7. Para o teste foram gerados 3 conjuntos de asset bundles, cada um com &lt;a href="https://docs.unity3d.com/550/Documentation/Manual/AssetBundleCompression.html" target="_blank" rel="noreferrer"&gt;opção de compressão&lt;/a&gt;:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;No compression: sem compressão, carregamento rápido.&lt;/li&gt;&#10;&lt;li&gt;LZMA: menor tamanho de arquivo, porém mais lento para carregar por causa da descompressão.&lt;/li&gt;&#10;&lt;li&gt;LZ4: compressão com tamanho maior, porém, descompressão mais rápida.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2020/08/assetbundles-build.webp"&gt;&#10;&lt;/figure&gt;&#10;&#10;&lt;h3 class="relative group"&gt;Teste&#10; &lt;div id="teste" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#teste" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;Para realizar o teste escrevi um script bem simples para gerar todas as builds Android, as quais iriam utilizar no teste, considerando as seguintes variações e resultado em um total de 27 APKs:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Scripting backend: Mono, IL2CPP&lt;/li&gt;&#10;&lt;li&gt;Architecture: ARMv7, ARM64&lt;/li&gt;&#10;&lt;li&gt;Build compression: Default, LZ4, LZ4HC&lt;/li&gt;&#10;&lt;li&gt;Asset bundles compression: No compression, LZMA, LZ4&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Com os 27 APKs gerados, instalei cada um no aparelho, sempre desinstalando o anterior. Cada APK foi iniciado apenas uma vez, com os seguintes dados coletados:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Tamanho da builds&lt;/li&gt;&#10;&lt;li&gt;Tempo até executar o método Awake() no único MonoBehaviour em um Game Object na Scene&lt;/li&gt;&#10;&lt;li&gt;Tamanho do asset bundle&lt;/li&gt;&#10;&lt;li&gt;Média do tempo para carregar um asset bundle usando a API AssetBundle.LoadFromFileAsync()&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;O projeto de teste contém 5 asset bundles, todos são cubos padrões da Unity com um material diferente em cada para modificar a cor (green, orange, purple, red, yellow). Cada asset bundle foi carregado sequencialmente, e o tempo considerado foi a média do tempo para carregar cada um deles.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;IEnumerator&lt;/span&gt; &lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CreateCube&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;green&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;cube_green&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Vector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CreateCube&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;orange&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;cube_orange&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Vector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1.5f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CreateCube&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;purple&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;cube_purple&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Vector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="m"&gt;1.5f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CreateCube&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;red&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;cube_red&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Vector3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1.5f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;CreateCube&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;yellow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;cube_yellow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Vector3&lt;/span&gt;&lt;span class="p"&gt;(-&lt;/span&gt;&lt;span class="m"&gt;1.5f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;IEnumerator&lt;/span&gt; &lt;span class="n"&gt;CreateCube&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;bundleName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;assetName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Vector3&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;streamingAssetsPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bundleName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;AssetBundleCreateRequest&lt;/span&gt; &lt;span class="n"&gt;assetBundleRequest&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AssetBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoadFromFileAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;assetBundleRequest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;GameObject&lt;/span&gt; &lt;span class="n"&gt;sphere&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;assetBundleRequest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assetBundle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoadAsset&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GameObject&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;assetName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Instantiate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sphere&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sphere&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;O script acima é uma versão simplificada do que utilizei para o teste. Omiti os logs e medições para mostrar como carreguei cada asset bundle e instanciei o game object.&lt;/p&gt;&#10;&#10;&lt;h3 class="relative group"&gt;Resultado&#10; &lt;div id="resultado" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#resultado" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;O resultado das 27 execuções de cada build está na tabela abaixo, ordenada pelo menor tempo médio para carregar um asset bundle.&lt;/p&gt;&#10;&lt;table&gt;&#10;&lt;tr&gt;&lt;th&gt;Build&lt;/th&gt;&lt;th&gt;Backend&lt;/th&gt;&lt;th&gt;Arch.&lt;/th&gt;&lt;th&gt;APK&lt;/th&gt;&lt;th&gt;Startup&lt;/th&gt;&lt;th&gt;Bundle&lt;/th&gt;&lt;th&gt;Size&lt;/th&gt;&lt;th&gt;Avg. ^&lt;/th&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4HC&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARM64&lt;/td&gt;&lt;td&gt;84.5MB&lt;/td&gt;&lt;td&gt;2.04s&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;15.4MB&lt;/td&gt;&lt;td&gt;46.4ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4HC&lt;/td&gt;&lt;td&gt;Mono&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;94.5MB&lt;/td&gt;&lt;td&gt;2.14s&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;15.4MB&lt;/td&gt;&lt;td&gt;49.4ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4HC&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARM64&lt;/td&gt;&lt;td&gt;46.2MB&lt;/td&gt;&lt;td&gt;2.03s&lt;/td&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;7.7MB&lt;/td&gt;&lt;td&gt;50ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARM64&lt;/td&gt;&lt;td&gt;84.6MB&lt;/td&gt;&lt;td&gt;2.04s&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;15.4MB&lt;/td&gt;&lt;td&gt;52.4ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;Default&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARM64&lt;/td&gt;&lt;td&gt;84.5MB&lt;/td&gt;&lt;td&gt;2.04s&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;15.4MB&lt;/td&gt;&lt;td&gt;54.8ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARM64&lt;/td&gt;&lt;td&gt;46.2MB&lt;/td&gt;&lt;td&gt;2.04s&lt;/td&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;7.7MB&lt;/td&gt;&lt;td&gt;55.4ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;45.6MB&lt;/td&gt;&lt;td&gt;2.03s&lt;/td&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;7.7MB&lt;/td&gt;&lt;td&gt;55.8ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4HC&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;84.0MB&lt;/td&gt;&lt;td&gt;2.03s&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;15.4MB&lt;/td&gt;&lt;td&gt;56ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;84.0MB&lt;/td&gt;&lt;td&gt;2.04s&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;15.4MB&lt;/td&gt;&lt;td&gt;56.8ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;Default&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARM64&lt;/td&gt;&lt;td&gt;46.1MB&lt;/td&gt;&lt;td&gt;2.04s&lt;/td&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;7.7MB&lt;/td&gt;&lt;td&gt;57.6ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4HC&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;45.6MB&lt;/td&gt;&lt;td&gt;2.03s&lt;/td&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;7.7MB&lt;/td&gt;&lt;td&gt;57.8ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;Mono&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;94.6MB&lt;/td&gt;&lt;td&gt;2.14s&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;15.4MB&lt;/td&gt;&lt;td&gt;58.2ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;Default&lt;/td&gt;&lt;td&gt;Mono&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;56.1MB&lt;/td&gt;&lt;td&gt;2.14s&lt;/td&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;7.7MB&lt;/td&gt;&lt;td&gt;59.8ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;Default&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;83.9MB&lt;/td&gt;&lt;td&gt;2.04s&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;15.4MB&lt;/td&gt;&lt;td&gt;61.2ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;Default&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;45.5MB&lt;/td&gt;&lt;td&gt;2.03s&lt;/td&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;7.7MB&lt;/td&gt;&lt;td&gt;61.4ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;Default&lt;/td&gt;&lt;td&gt;Mono&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;94.5MB&lt;/td&gt;&lt;td&gt;2.13s&lt;/td&gt;&lt;td&gt;No&lt;/td&gt;&lt;td&gt;15.4MB&lt;/td&gt;&lt;td&gt;62.4ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;Mono&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;56.2MB&lt;/td&gt;&lt;td&gt;2.13s&lt;/td&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;7.7MB&lt;/td&gt;&lt;td&gt;62.8ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4HC&lt;/td&gt;&lt;td&gt;Mono&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;56.2MB&lt;/td&gt;&lt;td&gt;2.13s&lt;/td&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;7.7MB&lt;/td&gt;&lt;td&gt;67.8ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4HC&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARM64&lt;/td&gt;&lt;td&gt;39.4MB&lt;/td&gt;&lt;td&gt;2.03s&lt;/td&gt;&lt;td&gt;LZMA&lt;/td&gt;&lt;td&gt;6.4MB&lt;/td&gt;&lt;td&gt;1331.6ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;Default&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARM64&lt;/td&gt;&lt;td&gt;39.3MB&lt;/td&gt;&lt;td&gt;2.03s&lt;/td&gt;&lt;td&gt;LZMA&lt;/td&gt;&lt;td&gt;6.4MB&lt;/td&gt;&lt;td&gt;1343ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;Mono&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;49.4MB&lt;/td&gt;&lt;td&gt;2.13s&lt;/td&gt;&lt;td&gt;LZMA&lt;/td&gt;&lt;td&gt;6.4MB&lt;/td&gt;&lt;td&gt;1355.8ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARM64&lt;/td&gt;&lt;td&gt;39.4MB&lt;/td&gt;&lt;td&gt;2.03s&lt;/td&gt;&lt;td&gt;LZMA&lt;/td&gt;&lt;td&gt;6.4MB&lt;/td&gt;&lt;td&gt;1358.6ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4HC&lt;/td&gt;&lt;td&gt;Mono&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;49.4MB&lt;/td&gt;&lt;td&gt;2.13s&lt;/td&gt;&lt;td&gt;LZMA&lt;/td&gt;&lt;td&gt;6.4MB&lt;/td&gt;&lt;td&gt;1369.2ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;38.8MB&lt;/td&gt;&lt;td&gt;2.04s&lt;/td&gt;&lt;td&gt;LZMA&lt;/td&gt;&lt;td&gt;6.4MB&lt;/td&gt;&lt;td&gt;1376.4ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;LZ4HC&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;38.8MB&lt;/td&gt;&lt;td&gt;2.03s&lt;/td&gt;&lt;td&gt;LZMA&lt;/td&gt;&lt;td&gt;6.4MB&lt;/td&gt;&lt;td&gt;1378.8ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;Default&lt;/td&gt;&lt;td&gt;IL2CPP&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;38.7MB&lt;/td&gt;&lt;td&gt;2.04s&lt;/td&gt;&lt;td&gt;LZMA&lt;/td&gt;&lt;td&gt;6.4MB&lt;/td&gt;&lt;td&gt;1394ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;tr&gt;&lt;td&gt;Default&lt;/td&gt;&lt;td&gt;Mono&lt;/td&gt;&lt;td&gt;ARMv7&lt;/td&gt;&lt;td&gt;49.3MB&lt;/td&gt;&lt;td&gt;2.13s&lt;/td&gt;&lt;td&gt;LZMA&lt;/td&gt;&lt;td&gt;6.4MB&lt;/td&gt;&lt;td&gt;1414.8ms&lt;/td&gt;&lt;/tr&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;Legenda da tabela:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Build: compression method do Build Settings&lt;/li&gt;&#10;&lt;li&gt;Backend: scripting backend do Player Settings&lt;/li&gt;&#10;&lt;li&gt;Arch.: architecture do Player Settings&lt;/li&gt;&#10;&lt;li&gt;APK: tamanho do APK&lt;/li&gt;&#10;&lt;li&gt;Startup: tempo até carregar o MonoBehaviour&lt;/li&gt;&#10;&lt;li&gt;Bundle: compression do Asset Bundle Build&lt;/li&gt;&#10;&lt;li&gt;Size: tamanho do asset bundle&lt;/li&gt;&#10;&lt;li&gt;Avg.: tempo médio para carregar um asset bundle&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&#10;&lt;h3 class="relative group"&gt;Conclusão&#10; &lt;div id="conclusão" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#conclus%c3%a3o" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h3&gt;&#10;&lt;p&gt;O projeto utilizado no teste era bem pequeno e, apesar do foco ser a compressão de asset bundles, foi interessante ver como as demais configurações influenciam no todo. Qual a melhor configuração para o seu projeto? &lt;strong&gt;Depende&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;p&gt;Não comprimir asset bundles faz o carregamento ser muito rápido, porém, isso aumenta tanto o tamanho dos arquivos baixados e da build (quando possuem asset bundles), o que é bem raro um jogo grande utilizar. A compressão LZMA deixa um tamanho menor para download, reduzindo o tempo para o jogador poder jogar e até diminuindo o custo do CDN, porém, aumenta bastante o tempo de loading por causa da descompressão. O LZ4 pode ser o melhor dos dois mundos, sendo relativamente rápido para carregar e não tão pesado, mas ainda assim depende muito do projeto.&lt;/p&gt;&#10;&lt;p&gt;Já nas configurações específicas do Android, LZ4HC mostrou um bom desempenho para carregar o jogo, assim como o IL2CPP. Sempre que possível inclua as duas arquiteturas, ARMv7 e ARM64, no APK ou no Android App Bundle (AAB) - o Android vai fazer o resto e decidir qual é a melhor arquitetura presente no app para ser utilizada. No caso do teste, eu forcei builds apenas com ARMv7 e ARM64 para poder comparar os resultados, já que se incluísse ambas apenas a ARM64 seria utilizada.&lt;/p&gt;&#10;&lt;p&gt;Lembrando novamente que, este teste foi realizado em um projeto pequeno e simples, mas que serviu para mostrar qual seria a melhor combinação para este jogo. Mais do que isso, este teste mostra que existem muitas variáveis nas configurações do projeto na Unity, as quais podem influenciar bastante a performance do jogo, e conhecê-las te ajudará a escolher qual é a melhor para seu projeto. Lembre-se de não decidir sem testar, algumas horas do seu dia podem melhorar muito o desempenho do seu jogo.&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/categories/unity.webp" medium="image"/></item><item><title>Um ótimo tutorial feito pela Unity para criar um Flappy Bird</title><link>https://gamedeveloper.com.br/unity-video-tutorial-flappy-bird/</link><guid>https://gamedeveloper.com.br/unity-video-tutorial-flappy-bird/</guid><pubDate>Sat, 18 Apr 2020 00:00:00 +0000</pubDate><category>Unity</category><description>Este tutorial chamado Making A Flappy Bird Style Game feito pela Unity esta disponível no site Unity Learn e é dividido em 10 partes. Não é um tutorial novo, foi publicado em 2006, porém existem muitas coisas interessantes nestes vídeos que ainda são bem atuais para desenvolvimento de jogos 2D na Unity, além de muitas dicas de como ser mais produtivo no editor.&#10;</description><content:encoded>&lt;p&gt;Este tutorial chamado &lt;a href="https://learn.unity.com/tutorial/live-session-making-a-flappy-bird-style-game" target="_blank" rel="noreferrer"&gt;Making A Flappy Bird Style Game&lt;/a&gt; feito pela &lt;a href="https://unity.com/" target="_blank" rel="noreferrer"&gt;Unity&lt;/a&gt; esta disponível no site &lt;a href="https://learn.unity.com" target="_blank" rel="noreferrer"&gt;Unity Learn&lt;/a&gt; e é dividido em 10 partes. Não é um tutorial novo, foi publicado em 2006, porém existem muitas coisas interessantes nestes vídeos que ainda são bem atuais para desenvolvimento de jogos 2D na Unity, além de muitas dicas de como ser mais produtivo no editor.&lt;/p&gt;&#10;&lt;p&gt;Esta série de vídeos, que tem menos de 2 horas no total, é um conteúdo rápido e muito bom para aprender algumas coisas básicas na Unity, além de exemplos de design patterns na prática. Eu recomendo pra quem tem experiência com Unity também, pois sempre temos algo a aprender. Eu assiti todo o curso e realmente aprendi e relembrei algumas coisas.&lt;/p&gt;&#10;&lt;p&gt;Os vídeos estão disponíveis no site &lt;a href="https://learn.unity.com" target="_blank" rel="noreferrer"&gt;Unity Learn&lt;/a&gt; e também no &lt;a href="https://www.youtube.com/playlist?list=PLX2vGYjWbI0QBJUI5wI3lBTaz85k37dwo" target="_blank" rel="noreferrer"&gt;canal da Unity&lt;/a&gt; no Youtube. Listei todos abaixo, mas recomendo fortemente acompanhar pelo site da Unity Learn por que em cada vídeo tem o código em seguida pra você ver em detalhes.&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/WWn4i5u2pWY" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/Z0mNwITrCnQ" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/Sz6hj2uq86U" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/HLosu_cy6Ok" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/NegDFzLGT7U" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/pbFFjgCVaHY" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/AyNhGthBFdg" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/UbPrBZM3xfU" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/hn5LD17n1wc" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/BmSJ-w8ZVxc" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;Vale lembrar que todo conteúdo premium da &lt;a href="https://learn.unity.com" target="_blank" rel="noreferrer"&gt;Unity Learn&lt;/a&gt; está disponível de graça por um tempo. O conteúdo criado pela Unity é muito bom, e tem vídeos para todas as áreas - de arte a programação. Aproveita que você está em casa e assiste alguns dos vídeos, e depois comenta aqui os que você mais gostou de ver lá.&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/categories/unity.webp" medium="image"/></item><item><title>Como criar e utilizar um Unity Package</title><link>https://gamedeveloper.com.br/custom-unity-packages/</link><guid>https://gamedeveloper.com.br/custom-unity-packages/</guid><pubDate>Sun, 01 Mar 2020 00:00:00 +0000</pubDate><category>Unity</category><description>Uma forma comum de compartilhar código, modulos e até plugins nativos sempre foi criar um package - exportar um arquivo .unitypackage para ser importado em outro projeto. É uma forma prática de distribuir conteúdo para Unity, porém tem problemas como falta de versionamento, não ter um canal de distribuição centralizado, não avisar de atualizações, permitir que seu conteúdo seja modificado ou removido, entre outros. Isso tudo, quando existia, dependia do desenvolvedor criar uma ferramenta para controlar a integridade e o versionamento do pacote.&#10;</description><content:encoded>&lt;p&gt;Uma forma comum de compartilhar código, modulos e até plugins nativos sempre foi &lt;a href="https://docs.unity3d.com/2018.4/Documentation/Manual/HOWTO-exportpackage.html" target="_blank" rel="noreferrer"&gt;criar um package&lt;/a&gt; - exportar um arquivo &lt;code&gt;.unitypackage&lt;/code&gt; para ser importado em outro projeto. É uma forma prática de distribuir conteúdo para Unity, porém tem problemas como falta de versionamento, não ter um canal de distribuição centralizado, não avisar de atualizações, permitir que seu conteúdo seja modificado ou removido, entre outros. Isso tudo, quando existia, dependia do desenvolvedor criar uma ferramenta para controlar a integridade e o versionamento do pacote.&lt;/p&gt;&#10;&lt;p&gt;Felizmente, a Unity criou uma ferramenta que ajuda em todos os pontos acima e mais alguns, chamada &lt;a href="https://docs.unity3d.com/Manual/Packages.html" target="_blank" rel="noreferrer"&gt;Unity Package Manager&lt;/a&gt;. Para utilizá-lo, é necessário criar um projeto seguindo o &lt;a href="https://docs.unity3d.com/Packages/com.unity.package-manager-ui@1.8/manual/index.html" target="_blank" rel="noreferrer"&gt;padrão de package&lt;/a&gt;, que pode depois ser importado como um projeto local, um tarball, um repositório git, e até distribuído por &lt;a href="https://www.npmjs.com/" target="_blank" rel="noreferrer"&gt;npm&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p&gt;Neste post vou falar mostrar como eu fiz para criar o meu package chamado &lt;code&gt;Cicanci Utils&lt;/code&gt; e como configurei para ele ser distribuído em um repositório público no GitHub. O conteúdo do package em si é bem básico no momento - apenas um script para enviar e receber mensagens que &lt;a href="https://gamedeveloper.com.br/unity-message-manager/" &gt;criei neste post&lt;/a&gt;. Minha ideia é adicionar mais scripts úteis neste package, sempre com algum post explicando seu funcionamento.&lt;/p&gt;&#10;&#10;&lt;h1 class="relative group"&gt;Criando um package&#10; &lt;div id="criando-um-package" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#criando-um-package" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h1&gt;&#10;&lt;p&gt;Criar um package é bem simples, e começa com um projeto novo na Unity. Depois de criar um projeto novo, você precisa criar os seguintes arquivos, sendo que alguns são obrigatórios como o &lt;code&gt;package.json&lt;/code&gt; e a estrutura abaixo para código e teste.&lt;/p&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2020/03/package-structure.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;p&gt;O &lt;code&gt;package.json&lt;/code&gt; é um arquivo com toda informação necessária sobre o pacote, e é o que vai ser exibido na janela do Package Manager. Este arquivo contém campos importantes como nome, versão do pacote, versão mínima suportada, e dependencias de outros packages. Abaixo está o exemplo do meu, que contém também dados de autor, palavras-chave e o tipo do pacote.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;com.cicanci.unity-utils&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;version&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1.0.0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;displayName&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Cicanci Utils&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;description&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Useful pieces of code for Unity projects.&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;unity&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2017.4&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;keyworks&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;library&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;utility&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="s2"&gt;&amp;#34;utils&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;],&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;author&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Bruno Cicanci&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;email&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;bruno@cicanci.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;url&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://cicanci.com&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;},&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;library&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&#10;&lt;h1 class="relative group"&gt;Adicionando conteúdo&#10; &lt;div id="adicionando-conteúdo" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#adicionando-conte%c3%bado" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h1&gt;&#10;&lt;p&gt;No meu caso, eu criei um package do tipo &lt;code&gt;library&lt;/code&gt; e adicionei o código do pacote em uma pasta chamada &lt;code&gt;Runtime&lt;/code&gt; e os testes unitários em uma outra pasta chamada &lt;code&gt;Test\Runtime&lt;/code&gt;. Além dos scripts, é necessário criar um arquivo &lt;code&gt;asmdef&lt;/code&gt; para cada um desses dois diretórios. Dentro destas pastas pode ter a estrutura de namespace que você quiser.&lt;/p&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2020/03/runtime-test.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;p&gt;Para funcionar os testes eu tive que adicionar no &lt;code&gt;asmdef&lt;/code&gt; dele uma referência para o pacote da Unity chamado &lt;code&gt;Test Runner&lt;/code&gt; (engine e editor). Caso contrário, um erro de compilação acontece por que uma pasta com &lt;code&gt;asmdef&lt;/code&gt; não consegue importar e usar namespaces de pacotes que não estão adicionados como referência, além da API padrão da Unity.&lt;/p&gt;&#10;&#10;&lt;h1 class="relative group"&gt;Publicando no GitHub&#10; &lt;div id="publicando-no-github" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#publicando-no-github" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h1&gt;&#10;&lt;p&gt;Eu tive alguns problemas para publicar o package no GitHub e fazer ele ser reconhecido pela Unity. O primeiro problema é a estrutura, pois a Unity não reconhece como um package um projeto na raiz do repositório. Para funcionar é necessário adicionar o conteúdo do package direto na raiz do repositório, como mostrado na image abaixo.&lt;/p&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2020/03/repositorio.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;p&gt;O segundo problema que tive, depois que resolvi a estrutura do repositório, foi com os arquivos &lt;code&gt;.meta&lt;/code&gt;. Eu acho que não eram necessários, já que no repositório não é mais um projeto Unity. Porém, eu estava enganado e é necessário sim adicionar estes arquivos.&lt;/p&gt;&#10;&lt;p&gt;Esta estrutura é bem simples, porém dificulta um pouco na hora de atualizar o pacote e publicar. A melhor maneira que encontrei foi criar um projeto na Unity e clonar o repositório dentro dele. Provavelmente existe alguma maneira melhor de manter um package publicado no GitHub, se você souber por favor comenta a baixo.&lt;/p&gt;&#10;&lt;p&gt;Eu publiquei como um repositório público por ser mais simples e poder realmente divulgar o package, porém também é possível configurar um repositório privado para ser usado na sua empresa ou em seus projetos, por exemplo. Não li sobre como fazer, mas li que é possível sim com alguma configuração a mais.&lt;/p&gt;&#10;&#10;&lt;h1 class="relative group"&gt;Importando em seu projeto&#10; &lt;div id="importando-em-seu-projeto" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#importando-em-seu-projeto" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h1&gt;&#10;&lt;p&gt;Por fim, vamos a parte da utilização do package. É bem simples, basta abrir o Package Manager e adicionar um novo package como &lt;code&gt;git URL&lt;/code&gt;. Você pode adicionar o link &lt;code&gt;SSH&lt;/code&gt; ou &lt;code&gt;HTTPS&lt;/code&gt;, ambos funcionam. No meu pacote o link é &lt;code&gt;https://github.com/cicanci/cicanci-utils.git&lt;/code&gt;.&lt;/p&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2020/03/importar-1.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2020/03/importar-2.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2020/03/importar-3.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;p&gt;Depois de importado, basta usar como normalmente é feito. Importe o namespace na sua classe e está pronto para utilizar todo conteúdo do package. Abaixo está um exemplo de uso, que também está disponível no &lt;a href="https://github.com/cicanci/cicanci-utils" target="_blank" rel="noreferrer"&gt;README do repositório&lt;/a&gt;.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Cicanci.Utils&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;UnityEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageBehaviour&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MessageManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddListener&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;OnMessageReceived&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;OnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MessageManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RemoveListener&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;OnMessageReceived&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;OnMessageReceived&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MyMessage&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Debug&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Greetings&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;SendMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MyMessage&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;MyMessage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;Greetings&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;MessageManager&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyMessage&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Greetings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&#10;&lt;h1 class="relative group"&gt;Conclusão&#10; &lt;div id="conclusão" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#conclus%c3%a3o" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h1&gt;&#10;&lt;p&gt;Apesar de dar um pouco mais de trabalho para configurar do que apenas exportar seu projeto como um &lt;code&gt;.unitypackage&lt;/code&gt;, as vantagens de utilizar o novo sistema de package é bem grande. É bem simples para outros desenvolvedores usarem seu código e conteúdo, e mais fácil para manter atualizado e organizado seguindo um padrão pré-definido pela engine.&lt;/p&gt;&#10;&lt;p&gt;Meu package &lt;code&gt;Cicanci Utils&lt;/code&gt; é bem simples e pequeno, eu criei apenas para estudar como criar e distribuir um pacote, e poder postar o resultado aqui no blog. Minha idea é adicionar mais scripts úteis neste package, junto com posts explicando o que tem de novo nele. É bom ter um lugar organizado e centralizado onde posso jogar meus scripts que uso com frequência ao invés de copiar e colar de outros projetos.&lt;/p&gt;&#10;&lt;p&gt;Vou deixar uma referência muito boa que é este vídeo do &lt;a href="https://www.youtube.com/channel/UCTjnCCcuIbrprhOiaDJxxHA" target="_blank" rel="noreferrer"&gt;canal Infallible Code&lt;/a&gt; explicando praticamente tudo que escrevi neste post, com exceção da parte de publicá-lo no GitHub. Recomendo assistir os demais vídeos deste canal, o conteúdo é muito bom.&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/OhwP5TYgucM" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;O que você achou do Package Manager? Usaria em seu projeto? Se já usou e tem dicas para compartilhar, deixe um comentário abaixo.&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/categories/unity.webp" medium="image"/></item><item><title>Dicas para teste técnico com Unity #2</title><link>https://gamedeveloper.com.br/dicas-teste-tecnico-unity-2/</link><guid>https://gamedeveloper.com.br/dicas-teste-tecnico-unity-2/</guid><pubDate>Mon, 14 Oct 2019 00:00:00 +0000</pubDate><category>Unity</category><description>Este é o segundo post da série com dicas para teste técnico utilizando Unity e C#. No primeiro post, o foco foi como organizar o projeto para facilitar seu desenvolvimento, e como enviar após o término. Agora, vamos falar um pouco de código, cobrindo um dos erros comuns que vejo em testes técnicos, especialmente relacionado a API da Unity.&#10;</description><content:encoded>&lt;p&gt;Este é o segundo post da série com dicas para teste técnico utilizando Unity e C#. No &lt;a href="https://gamedeveloper.com.br/dicas-teste-tecnico-unity-1/" &gt;primeiro post&lt;/a&gt;, o foco foi como organizar o projeto para facilitar seu desenvolvimento, e como enviar após o término. Agora, vamos falar um pouco de código, cobrindo um dos erros comuns que vejo em testes técnicos, especialmente relacionado a API da Unity.&lt;/p&gt;&#10;&lt;p&gt;Nesta série de posts sobre dicas para teste técnico, o assunto código vai ser bem recorrente, mas não vamos deixar de lado tópicos relacionados a configuração da engine, e features que podemos usar sem necessariamente escrever código pra isso. A Unity possui diversas ferramentas, e meu objetivo aqui vai ser sempre ajudar a evitar alguns erros comuns e mostrar o que é interessante demonstrar em um teste técnico nesta engine.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;Uso do GetComponent na Unity&#10; &lt;div id="uso-do-getcomponent-na-unity" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#uso-do-getcomponent-na-unity" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;Meu objetivo não é falar para usar ou não usar uma determinada chamada da API da Unity, mas sim mostrar o lugar ideal para colocá-la quando utilizada. Vamos começar por uma das mais comuns: &lt;code&gt;GetComponent&lt;/code&gt;, utilizado para buscar um componente, de um tipo específico, no &lt;code&gt;gameObject&lt;/code&gt;. O &lt;a href="https://docs.unity3d.com/ScriptReference/GameObject.GetComponent.html" target="_blank" rel="noreferrer"&gt;GetComponent&lt;/a&gt; possui algumas variações, como: &lt;code&gt;GetComponents&lt;/code&gt;, para retornar uma lista de um tipo; o &lt;code&gt;GetComponentInParent&lt;/code&gt;, que busca no pai do &lt;code&gt;gameObject&lt;/code&gt;; e o &lt;code&gt;GetComponentInChildren&lt;/code&gt;, que busca no filho do &lt;code&gt;gameObject&lt;/code&gt;. Estes dois últimos também possuem uma variação para retornar uma lista do tipo desejado.&lt;/p&gt;&#10;&lt;p&gt;Vamos para alguns exemplos e, nos códigos a seguir, imagine que o script está em um &lt;code&gt;gameObject&lt;/code&gt; na scene. No código abaixo, você consegue identificar qual é o problema?&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyGame&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Awake&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;GetComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SpriteRenderer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Neste exemplo, estamos buscando o componente &lt;code&gt;SpriteRenderer&lt;/code&gt; e assumindo que ele existe para, logo em seguida, mudar o valor de uma propriedade sua. Se o componente não existir, vamos gerar um &lt;code&gt;NullReferenceException&lt;/code&gt; logo no &lt;code&gt;Awake()&lt;/code&gt; do &lt;code&gt;MonoBehaviour&lt;/code&gt;. Vamos modificar um pouco o código para corrigir isso.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyGame&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Awake&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SpriteRenderer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;GetComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SpriteRenderer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Parece mais seguro agora, não? Evitamos o uso do &lt;code&gt;NullReferenceException&lt;/code&gt;, mas ainda tem algo que não é o ideal ali. Estamos usando duas vezes a chamada do &lt;code&gt;GetComponent()&lt;/code&gt;, podemos reduzir para uma chamada com a modificação abaixo.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyGame&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Awake&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;spriteRenderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SpriteRenderer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;spriteRenderer&lt;/span&gt; &lt;span class="p"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;spriteRenderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Podemos, também, garantir que o objeto vai ter um &lt;a href="https://docs.unity3d.com/ScriptReference/RequireComponent.html" target="_blank" rel="noreferrer"&gt;determinado script anexado&lt;/a&gt; usando o &lt;code&gt;RequireComponent&lt;/code&gt;, assim não precisamos verificar se o componente existe.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt;[RequireComponent(typeof(SpriteRenderer))]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyGame&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Awake&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;spriteRenderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SpriteRenderer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;spriteRenderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Voltando um pouco, vamos falar agora o que o &lt;code&gt;GetComponent&lt;/code&gt; faz por trás da chamada. O &lt;a href="https://github.com/Unity-Technologies/UnityCsReference/blob/master/Runtime/Export/Scripting/Component.bindings.cs#L42" target="_blank" rel="noreferrer"&gt;código C# da Unity&lt;/a&gt; está no seu GitHub para ser usado como referência, assim fica fácil de ver o que alguma determinada API faz. Não é o código inteiro da engine, apenas a parte C#, mas já ajuda muito a aprender o que cada API faz. No caso, o &lt;code&gt;GetComponent&lt;/code&gt; faz isso:&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;unsafe&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;GetComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CastHelper&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;GetComponentFastPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IntPtr&lt;/span&gt;&lt;span class="p"&gt;(&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;onePointerFurtherThanT&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;Não precisa ser muito experiente em C# para ver que existem duas alocações ali, um &lt;code&gt;CastHelper&lt;/code&gt; e um &lt;code&gt;System.IntPtr&lt;/code&gt;, além do que o &lt;code&gt;GetComponentFastPath()&lt;/code&gt; deve executar no código C++ da Unity (essa parte não está disponível para consulta). Não é muita coisa, e não é algo que vai fazer muita diferença de performance, mas podemos evitar o uso do &lt;code&gt;GetComponent&lt;/code&gt; em alguns casos, como o exemplo abaixo, onde a variável é recebida pelo Inspector, e podemos até usar o &lt;code&gt;GetComponent&lt;/code&gt; caso ela não seja referenciada no &lt;code&gt;gameObject&lt;/code&gt;.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyGame&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [SerializeField]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;SpriteRenderer&lt;/span&gt; &lt;span class="n"&gt;_spriteRenderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Awake&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_spriteRenderer&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_spriteRenderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GetComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SpriteRenderer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_spriteRenderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;enabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;A modificação acima não vai fazer muita diferença, o &lt;code&gt;GetComponent&lt;/code&gt; é rápido o suficiente pra não causar problemas de performance. Porém, com base em tudo que escrevi neste post, o código abaixo não é recomendado. É um caso exagerado onde queremos garantir que o &lt;code&gt;SpriteRenderer&lt;/code&gt; esteja desabilitado por qualquer motivo, usando um &lt;code&gt;Update()&lt;/code&gt; para a validação.&lt;/p&gt;&#10;&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cs" data-lang="cs"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyGame&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;MonoBehaviour&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;Update&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;GetComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SpriteRenderer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;GetComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SpriteRenderer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;().&lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&#10;&lt;p&gt;O código acima, em um projeto médio/grande, pode causar alguns problemas de performance, especialmente se esse padrão estiver espalhado pelo projeto e a plataforma algo for Android ou iOS. Aparelhos mais antigos podem ter uma redução no FPS ou apresentar algumas travadas rápidas em transições. Então, sempre que possível, &lt;strong&gt;faça cache do &lt;code&gt;GetComponent&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;&#10;&lt;p&gt;O post ficou um pouco longo, mas espero que eu tenha conseguido mostrar algumas maneiras de usar o &lt;code&gt;GetComponent&lt;/code&gt; e, principalmente, recomendações do que deve ser evitado. Tudo isso é analisado em um teste técnico, independente do tamanho do projeto, pois ajuda a entender como o programador pensar e o quanto conhece da Unity, a game engine em questão. Deixei passar algo no post? Usa o &lt;code&gt;GetComponent&lt;/code&gt; de alguma mandeira diferente? Comenta abaixo, sempre temos muito o que aprender, por isso compartilhar sempre acrescenta.&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/categories/unity.webp" medium="image"/></item><item><title>Canal no Youtube com tutorials em Unity</title><link>https://gamedeveloper.com.br/youtube-unity-code-monkey/</link><guid>https://gamedeveloper.com.br/youtube-unity-code-monkey/</guid><pubDate>Fri, 04 Oct 2019 00:00:00 +0000</pubDate><category>Unity</category><description>O canal no YouTube Code Monkey tem diversos vídeos muito bons sobre desenvolvimento de jogos, com uma ótima didática e bem resumidos. O autor do canal é um programador, que já publicou alguns dos seus jogos no Steam e, através do seu canal, compartilha tudo que já usou para fazer seus jogos utilizando Unity e C#.&#10;</description><content:encoded>&lt;p&gt;O canal no YouTube &lt;a href="https://www.youtube.com/channel/UCFK6NCbuCIVzA6Yj1G_ZqCg" target="_blank" rel="noreferrer"&gt;Code Monkey&lt;/a&gt; tem diversos vídeos muito bons sobre desenvolvimento de jogos, com uma ótima didática e bem resumidos. O autor do canal é um programador, que já publicou alguns dos seus &lt;a href="http://endlessloopstudios.com/" target="_blank" rel="noreferrer"&gt;jogos no Steam&lt;/a&gt; e, através do seu canal, compartilha tudo que já usou para fazer seus jogos utilizando Unity e C#.&lt;/p&gt;&#10;&lt;p&gt;No &lt;a href="https://unitycodemonkey.com/index.php" target="_blank" rel="noreferrer"&gt;site do Code Monkey&lt;/a&gt; estão todos os seus vídeos, como no YouTube, e algum conteúdo extra, como seu pacote &lt;a href="https://unitycodemonkey.com/utils.php" target="_blank" rel="noreferrer"&gt;Code Monkey Utilities&lt;/a&gt;, com diversos scripts muito úteis para acelearar o desenvolvimento de jogos na Unity, e também é usado em seus vídeos.&lt;/p&gt;&#10;&lt;p&gt;Vou listar alguns vídeos que gostei abaixo, não deixei de conferir o seu &lt;a href="https://www.youtube.com/channel/UCFK6NCbuCIVzA6Yj1G_ZqCg" target="_blank" rel="noreferrer"&gt;canal no YouTube&lt;/a&gt; para ver mais conteúdo. Outro canal muito bom, que já indiquei aqui no blog, é o &lt;a href="https://www.youtube.com/channel/UCYbK_tjZ2OrIZFBvU6CCMiA" target="_blank" rel="noreferrer"&gt;Brackeys&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/11c9rWRotJ8" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/nliDeB_OQP4" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/kWhOMJMihC0" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/images/2019/10/codemonkey.webp" medium="image"/></item><item><title>Humble Bundle Unity com cursos, ferramentas e assets</title><link>https://gamedeveloper.com.br/unity-humble-bundle/</link><guid>https://gamedeveloper.com.br/unity-humble-bundle/</guid><pubDate>Mon, 30 Sep 2019 00:00:00 +0000</pubDate><category>Unity</category><description>O Humble Bundle é um site que vende bundles (pacotes) com jogos ou livros digitais pelo preço que você quiser pagar, e ainda permite escolher dividir seu pagamento entre caridade e/ou para o desenvolvedor. Este mês ele fez uma parceria com a Unity e lançou um bundle contendo recursos e ferramentas da Asset Store, um curso do GameDevHQ, e 1 ano de acesso aos cursos do Unity Learn Premium.&#10;</description><content:encoded>&lt;p&gt;O &lt;a href="https://www.humblebundle.com/software/unity-2019-bundle" target="_blank" rel="noreferrer"&gt;Humble Bundle&lt;/a&gt; é um site que vende bundles (pacotes) com jogos ou livros digitais pelo preço que você quiser pagar, e ainda permite escolher dividir seu pagamento entre caridade e/ou para o desenvolvedor. Este mês ele fez uma parceria com a Unity e lançou um bundle contendo recursos e ferramentas da &lt;a href="https://assetstore.unity.com/" target="_blank" rel="noreferrer"&gt;Asset Store&lt;/a&gt;, um curso do &lt;a href="https://unity.gamedevhq.com/" target="_blank" rel="noreferrer"&gt;GameDevHQ&lt;/a&gt;, e 1 ano de acesso aos cursos do &lt;a href="https://learn.unity.com/" target="_blank" rel="noreferrer"&gt;Unity Learn Premium&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p&gt;A soma total de todo conteúdo do bundle é de mais de $1000 dólares, e você pode pagar apenas $15 dólares por tudo isso (valor mínimo para pegar tudo). Só os cursos do Unity Learn Premium já valem o preço e, além disso, alguns assets e ferramentas do pacote são essenciais para agilizar o desenvolvimento de um projeto ou até fazer um protótipo para testar uma ideia.&lt;/p&gt;&#10;&lt;p&gt;Vou colocar abaixo alguns vídeos de assets e ferramentas contidos nesse bundle, como: &lt;a href="https://assetstore.unity.com/packages/tools/integration/easy-mobile-pro-75476" target="_blank" rel="noreferrer"&gt;Eazy Mobile Pro&lt;/a&gt;, praticamente tudo que você precisa para um jogo mobile (IAP, Ads, Login, etc); &lt;a href="https://assetstore.unity.com/packages/tools/gui/doozyui-complete-ui-management-system-138361" target="_blank" rel="noreferrer"&gt;DoozyUI&lt;/a&gt;, para fluxos de UI; &lt;a href="https://assetstore.unity.com/packages/tools/particles-effects/aura-2-volumetric-lighting-fog-137148" target="_blank" rel="noreferrer"&gt;Aura 2&lt;/a&gt;, que possui efeitos incríveis de luz; e o famoso &lt;a href="https://assetstore.unity.com/packages/tools/visual-scripting/playmaker-368" target="_blank" rel="noreferrer"&gt;PlayMaker&lt;/a&gt;, uma ferramenta de visual scripting para Unity.&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/2ZsyvR69ICc" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/xCHvQHTpXzs" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;iframe style="width: 100%" height="400" src="https://www.youtube.com/embed/_v4vxIPWdAg" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;/p&gt;&#10;&lt;p&gt;O &lt;a href="https://www.humblebundle.com/software/unity-2019-bundle" target="_blank" rel="noreferrer"&gt;Humble Bundle Unity&lt;/a&gt; vai até o dia 14 de Outubro. Se você está começando a estudar Unity, recomendo pegar pelos cursos. Se você já tem experiência, recomendo pelos cursos e assets. Considerando a cotação do dólar de hoje esse bundle me custou R$70, um valor muito baixo pela quantidade de conhecimento e assets de qualidade incluídos no pacote. No lugar de comprar aquele jogo em promoção no Steam, aproveite para aprimorar seu conhecimento em Unity.&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/images/2019/09/humblebundle.webp" medium="image"/></item><item><title>Dicas para teste técnico com Unity #1</title><link>https://gamedeveloper.com.br/dicas-teste-tecnico-unity-1/</link><guid>https://gamedeveloper.com.br/dicas-teste-tecnico-unity-1/</guid><pubDate>Wed, 25 Sep 2019 00:00:00 +0000</pubDate><category>Unity</category><description>Parte do meu trabalho na Aquiris é avaliar testes e realizar entrevistas técnicas com candidatos. Nos últimos anos aplicando testes, percebi que existe um padrão de erros básicos que, infelizmente, são comuns até para Senior Programmers. Este será o primeiro de uma série com dicas e sugestões do que fazer e não fazer em um teste técnico, focando Unity e C#.&#10;</description><content:encoded>&lt;p&gt;Parte do meu trabalho na Aquiris é avaliar testes e realizar entrevistas técnicas com candidatos. Nos últimos anos aplicando testes, percebi que existe um padrão de erros básicos que, infelizmente, são comuns até para Senior Programmers. Este será o primeiro de uma série com dicas e sugestões do que fazer e não fazer em um teste técnico, focando Unity e C#.&lt;/p&gt;&#10;&lt;p&gt;Quando uma empresa de jogos pede para um candidato realizar um teste técnico utilizando Unity, pode ser algo desde criar um jogo do zero, corrigir ou expandir um projeto existente. A qualidade do código também é avaliada, mas parte do teste consiste em ver o conhecimento do candidato em desenvolvimento de jogos, boas práticas, organização e conhecimento na própria engine em questão. Antes de falar de assuntos mais técnicos, vamos começar com um bem simples: como enviar o teste.&lt;/p&gt;&#10;&#10;&lt;h2 class="relative group"&gt;Melhores práticas para enviar o resultado de um teste técnico&#10; &lt;div id="melhores-práticas-para-enviar-o-resultado-de-um-teste-técnico" class="anchor"&gt;&lt;/div&gt;&#10; &#10; &lt;span&#10; class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;&#10; &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#melhores-pr%c3%a1ticas-para-enviar-o-resultado-de-um-teste-t%c3%a9cnico" aria-label="Âncora"&gt;#&lt;/a&gt;&#10; &lt;/span&gt;&#10; &#10;&lt;/h2&gt;&#10;&lt;p&gt;Submeter o teste técnico feito na Unity não é simplesmente zipar toda a pasta do projeto e enviar. Isso requer &lt;strong&gt;não enviar&lt;/strong&gt; algumas pastas e arquivos, o que também é avaliado por demonstrar conhecimento da estrutura básica da Unity e boas práticas de organização do projeto. Um projeto Unity, basicamente, é composto pelas seguinte pastas:&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;Assets&lt;/code&gt;: Onde fica o projeto em si&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;Packages&lt;/code&gt;: JSON com as dependências do projeto&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;ProjectSettings&lt;/code&gt;: Configuração do projeto&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;Qualquer outra pasta além destas não é necessário adicionar, isso é o mínimo para rodar qualquer projeto Unity. Nunca inclua a pasta &lt;code&gt;Library&lt;/code&gt;, ela não é necessária para rodar o jogo e aumenta muito o tamanho do projeto. Se um zip contém mais de 1MB, eu ja suspeito que esta pasta, desnecessária para o projeto, foi incluída.&lt;/p&gt;&#10;&lt;p&gt;Se você utilizar um repositório git em um servíco como o GitHub (recomendo), na criação do repositório é possível escolher iniciar o repositório com um arquivo &lt;code&gt;.gitignore&lt;/code&gt; com a &lt;a href="https://github.com/github/gitignore/blob/master/Unity.gitignore" target="_blank" rel="noreferrer"&gt;configuração da Unity&lt;/a&gt; para ignorar qualquer arquivo e pasta desnecessária.&lt;/p&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2019/09/create-repo.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;p&gt;Outras recomendações são sempre criar o repositório como privado, já que é um teste técnico para uma vaga, e marcar a opção de adicionar o arquivo &lt;code&gt;README&lt;/code&gt;. Neste arquivo inclua toda e qualquer informação relevante sobre o projeto, como rodar o jogo e detalhes que sejam relevantes para o teste técnico. Use este arquivo para documentar o que for necessério, assim todas informações ficarão junto ao projeto/repositório, e não perdidas em um arquivo externo ou em um e-mail.&lt;/p&gt;&#10;&lt;p&gt;Configurando o repositório corretamente, além de facilitar o seu desenvolvimento, vai simplificar a submissão, pois você precisa apenas baixá-lo como zip e enviar. Isso é importante, envie como &lt;strong&gt;zip&lt;/strong&gt;. Quem vai revisar o teste técnico pode estar usando um macOS e não precisa ser obrigado a baixar um app pra descompactar rar ou outro formato diferente.&lt;/p&gt;&#10;&lt;figure&gt;&#10; &lt;img&#10; class="my-0 rounded-md"&#10; loading="lazy"&#10; decoding="async"&#10; fetchpriority="low"&#10; alt=""&#10; src="https://gamedeveloper.com.br/images/2019/09/download-zip.webp"&gt;&#10;&lt;/figure&gt;&#10;&lt;p&gt;Por fim, após ter o seu arquivo zip enxuto, envie por e-mail &lt;strong&gt;e&lt;/strong&gt; compartilhe através do Google Drive ou similares, assim a pessoa que receber o seu teste técnico vai ter mais de uma maneira de baixá-lo caso tenha algum problema. Enviar o resultado é uma tarefa simples, mas você ganhará pontos em se preocupar com estes detalhes.&lt;/p&gt;&#10;&lt;p&gt;Por mais que o tempo para fazer o teste técnico seja curto, você não levará mais do que alguns minutos para configurar o projeto e deixar tudo pronto para uma submissão tranquila, então falta de tempo não é desculpa para enviar o resultado do teste de qualquer jeito.&lt;/p&gt;&#10;&lt;p&gt;Gostou dessa dica? Comente abaixo compartilhando sua experiência realizando testes técnicos para vagas em desenvolvmento de jogos. No próximo post vou abortar um erro comum relacionado a programação e uso das APIs da Unity.&lt;/p&gt;</content:encoded><media:content url="https://gamedeveloper.com.br/categories/unity.webp" medium="image"/></item></channel></rss>