Eleve o nível de seu código com padrões de programação de jogos


Se você tem experiência com linguagens de programação orientadas a objetos, provavelmente já ouviu falar dos princípios SOLID, MVP, singleton, factory e padrões observer. Nosso novo e-book destaca as melhores práticas para usar esses princípios e padrões para criar uma arquitetura de código de jogo escalável em seu projeto Unity.
Para cada problema de design de software que você encontra, mil desenvolvedores já passaram por isso antes. Embora nem sempre seja possível pedir conselhos diretamente a eles, você pode aprender com as decisões deles por meio de padrões de design.
Ao implementar padrões comuns de design de programação de jogos em seu projeto Unity, você pode criar e manter com eficiência uma base de código limpa, organizada e legível, o que, por sua vez, cria uma base sólida para escalar seu jogo, sua equipe de desenvolvimento e seus negócios.
Em nossa comunidade, ouvimos com frequência que pode ser intimidador aprender a incorporar padrões e princípios de design, como SOLID e KISS, no desenvolvimento diário. É por isso que nosso e-book gratuito, Eleve o nível de seu código com padrões de programação de jogosexplica padrões de design bem conhecidos e compartilha exemplos práticos para usá-los em seu projeto Unity.
Escrito por especialistas internos e externos da Unity, o e-book é um recurso que pode ajudar a expandir a caixa de ferramentas do seu desenvolvedor e acelerar o sucesso do seu projeto. Continue lendo para ver uma prévia do que o guia contém.
Os padrões de projeto são soluções gerais para problemas comuns encontrados na engenharia de software. Essas não são soluções prontas que você pode copiar e colar no seu código, mas ferramentas adicionais que podem ajudá-lo a criar aplicativos maiores e escalonáveis quando usadas corretamente.
Ao integrar padrões de forma consistente em seu projeto, você pode melhorar a legibilidade do código e tornar sua base de código mais limpa. Os padrões de design não apenas reduzem a refatoração e o tempo gasto com testes, mas também aceleram os processos de integração e desenvolvimento.
No entanto, todo padrão de design vem com compensações, quer isso signifique estruturas adicionais para manter ou mais configuração no início. Você precisará fazer uma avaliação de custo-benefício para determinar se a vantagem justifica o trabalho extra necessário. É claro que essa avaliação varia de acordo com seu projeto.
KISS significa "keep it simple, stupid" (mantenha simples, estúpido). O objetivo desse princípio é evitar a complexidade desnecessária em um sistema, já que a simplicidade ajuda a aumentar os níveis de aceitação e interação do usuário.
Observe que "simples" não é igual a "fácil". Tornar algo simples significa torná-lo focado. Embora seja possível criar a mesma funcionalidade sem os padrões (e muitas vezes mais rapidamente), algo rápido e fácil não resulta necessariamente em algo simples.
Se não tiver certeza de que um padrão se aplica ao seu problema específico, você pode adiar até que ele se encaixe de forma mais natural. Não use um padrão porque ele é novo ou inédito para você. Use-o quando precisar.
É com esse espírito que o e-book foi criado. Mantenha o guia à mão como uma fonte de inspiração para novas formas de organizar seu código, e não como um conjunto rígido de regras a serem seguidas.
Agora, vamos abordar alguns dos principais princípios de design de software.

SOLID é um acrônimo mnemônico para cinco fundamentos básicos do design de software. Você pode pensar nelas como cinco regras básicas a serem lembradas durante a codificação, para garantir que os projetos orientados a objetos permaneçam flexíveis e passíveis de manutenção.
Os princípios SOLID foram apresentados pela primeira vez por Robert C. Martin no artigo Design Principles and Design Patterns. Publicados pela primeira vez em 2000, os princípios descritos ainda são aplicáveis hoje em dia e aos scripts C# em Unity:
- A responsabilidade única afirma que cada módulo, classe ou função é responsável por uma coisa e encapsula apenas essa parte da lógica.
- Aberto-fechado afirma que as classes devem ser abertas para extensão, mas fechadas para modificação; isso significa estruturar suas classes para criar um novo comportamento sem modificar o código original.
- A substituição de Liskov afirma que as classes derivadas devem ser substituíveis por sua classe base ao usar a herança.
- A segregação de interface afirma que nenhum cliente deve ser forçado a depender de métodos que não usa. Os clientes devem implementar apenas o que precisam.
- A inversão de dependência afirma que os módulos de alto nível não devem importar nada diretamente dos módulos de baixo nível. Ambos devem depender de abstrações.
No e-book, fornecemos exemplos ilustrados de cada princípio com explicações claras para usá-los no Unity. Em alguns casos, a adesão ao SOLID pode resultar em trabalho adicional no início. Talvez seja necessário refatorar algumas de suas funcionalidades em abstrações ou interfaces, mas geralmente há um retorno em economia de longo prazo.
Os princípios dominaram o design de software por quase duas décadas em nível empresarial, pois são muito adequados para aplicativos grandes e escalonáveis. Se você não tiver certeza de como usá-los, consulte o princípio KISS. Mantenha a simplicidade e não tente forçar os princípios em seus scripts apenas por fazer isso. Deixe que eles se posicionem organicamente por necessidade.
Se você tiver interesse em saber mais, confira a apresentação SOLID da Unite Austin 2017, feita por Dan Sagmiller, da Productive Edge.
Qual é a diferença entre um princípio de design e um padrão de design? Uma maneira de responder a essa pergunta é considerar o SOLID como uma estrutura ou uma abordagem fundamental para escrever código orientado a objetos. Embora os padrões de projeto sejam soluções ou ferramentas que podem ser implementadas para evitar problemas cotidianos de software, lembre-se de que eles não são receitas prontas para uso, nem algoritmos com etapas específicas para obter resultados específicos.
Um padrão de design pode ser visto como um projeto. É um plano geral que deixa a construção real por sua conta. Por exemplo, dois programas podem seguir o mesmo padrão, mas envolver códigos muito diferentes.
Quando os desenvolvedores encontram o mesmo problema na natureza, muitos deles inevitavelmente apresentam soluções semelhantes. Quando uma solução é repetida várias vezes, alguém pode "descobrir" um padrão e dar um nome formal a ele.
Muitos dos padrões de design de software atuais têm origem no trabalho seminal, Design Patterns: Elements of Reusable Object-Oriented Software por Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides. Este livro apresenta 23 desses padrões identificados em uma variedade de aplicações cotidianas.
Os autores originais são frequentemente chamados de "Gang of Four" (GoF), e você também ouvirá os padrões originais serem chamados de padrões GoF. Embora os exemplos citados sejam, em sua maioria, em C++ (e Smalltalk), você pode aplicar suas ideias a qualquer linguagem orientada a objetos, como o C#.
Desde que o Gang of Four publicou originalmente Design Patterns em 1994, os desenvolvedores estabeleceram dezenas de outros padrões orientados a objetos em diversos campos, incluindo o desenvolvimento de jogos.


Embora você possa trabalhar como programador de jogos sem estudar padrões de design, aprendê-los o ajudará a se tornar um desenvolvedor melhor. Afinal de contas, os padrões de design são rotulados como tal porque são soluções comuns para problemas bem conhecidos.
Os engenheiros de software os redescobrem o tempo todo no curso normal do desenvolvimento. Talvez você já tenha implementado alguns desses padrões sem querer.
Treine-se para procurá-los. Fazer isso pode ajudá-lo:
- Aprenda programação orientada a objetos: Os padrões de design não são segredos enterrados em uma publicação esotérica do StackOverflow. São formas comuns de superar os obstáculos cotidianos no desenvolvimento. Eles podem informá-lo sobre quantos outros desenvolvedores abordaram o mesmo problema - lembre-se, mesmo que você não esteja usando padrões, alguém está.
- Converse com outros desenvolvedores: Os padrões podem servir como uma abreviação ao tentar se comunicar como uma equipe. Mencione o "padrão de comando" ou "pool de objetos" e os desenvolvedores experientes da Unity saberão o que você está tentando implementar.
- Explore novas estruturas: quando você importa um pacote incorporado ou algo da Asset Store, inevitavelmente se depara com um ou mais padrões discutidos aqui. O reconhecimento de padrões de design o ajudará a entender como uma nova estrutura funciona, bem como o processo de pensamento envolvido em sua criação.
Conforme indicado anteriormente, nem todos os padrões de design se aplicam a todos os aplicativos de jogos. Não vá procurá-los com o martelo de Maslow; caso contrário, você encontrará apenas pregos.
Como qualquer outra ferramenta, a utilidade de um padrão de design depende do contexto. Cada um deles oferece um benefício em determinadas situações e também tem sua parcela de desvantagens. Toda decisão no desenvolvimento de software envolve compromissos.
Você está gerando muitos GameObjects em tempo real? Isso afeta seu desempenho? A reestruturação de seu código pode corrigir isso? Esteja ciente desses padrões de design e, quando for a hora certa, use-os em sua maleta de truques de desenvolvimento de jogos para resolver o problema em questão.
Além do Gang of Four's Design Patterns, o Game Programming Patterns de Robert Nystrom é outro recurso de destaque, atualmente disponível gratuitamente como uma edição baseada na Web. O autor detalha uma variedade de padrões de software de forma objetiva.
Em nosso novo e-book, você pode mergulhar nas seções que explicam os padrões de design comuns, como fábrica, pool de objetos, singleton, comando, estado e padrões de observador, além do Model View Presenter (MVP), entre outros. Cada seção explica o padrão, juntamente com seus prós e contras, e fornece um exemplo de como implementá-lo no Unity para que você possa otimizar seu uso em seu projeto.
A Unity já implementa vários padrões de desenvolvimento de jogos estabelecidos, poupando-lhe o trabalho de escrevê-los você mesmo. Isso inclui:
- Loop do jogo: No centro de todos os jogos há um loop infinito que deve funcionar independentemente da velocidade do relógio, pois o hardware que alimenta um aplicativo de jogo pode variar muito. Para levar em conta computadores de velocidades diferentes, os desenvolvedores de jogos geralmente precisam usar um intervalo de tempo fixo (com um conjunto de quadros por segundo) e um intervalo de tempo variável em que o mecanismo mede quanto tempo se passou desde o quadro anterior.
A Unity cuida disso, portanto, você não precisa implementá-lo por conta própria. Você só precisa gerenciar a jogabilidade usando métodos MonoBehaviour como Update, LateUpdate e FixedUpdate. - Atualizar: Em seu aplicativo de jogo, você geralmente atualiza o comportamento de cada objeto um quadro de cada vez. Embora você possa recriar isso manualmente no Unity, a classe MonoBehaviour faz isso automaticamente. Use os métodos Update, LateUpdate ou FixedUpdate apropriados para modificar seus GameObjects e componentes para um tique do relógio do jogo.
- Protótipo: Muitas vezes, você precisa copiar objetos sem afetar o original. Esse padrão de criação resolve o problema de duplicar e clonar um objeto para criar outros objetos semelhantes a ele. Dessa forma, você evita definir uma classe separada para gerar cada tipo de objeto em seu jogo.
O sistema Prefab da Unity implementa uma forma de prototipagem para GameObjects. Isso permite duplicar um objeto de modelo completo com seus componentes. Substitua propriedades específicas para criar variantes de Prefab ou aninhe Prefabs dentro de outros Prefabs para criar hierarquias. Use um modo especial de edição de Prefab para editar Prefabs isoladamente ou no contexto. - Componente: A maioria das pessoas que trabalham com Unity conhece esse padrão. Em vez de criar classes grandes com várias responsabilidades, crie componentes menores, cada um com uma função.
Se você usar a composição para escolher componentes, poderá combiná-los para obter um comportamento complexo. Adicione componentes Rigidbody e Collider para física, ou um MeshFilter e MeshRenderer para geometria 3D. Cada GameObjects é tão rico e exclusivo quanto sua coleção de componentes.

Tanto o e-book quanto um exemplo de projeto sobre o uso de padrões de design já estão disponíveis para download gratuito. Analise os exemplos e decida qual padrão de design é mais adequado ao seu projeto. À medida que ganhar experiência com eles, você reconhecerá como e quando eles podem aprimorar seu processo de desenvolvimento. Como sempre, incentivamos você a visitar o tópico do fórum e nos dizer o que achou do e-book e da amostra.
