Esta página fornece uma visão geral do PaddleBallSOo projeto de demonstração que acompanha o livro eletrônico Crie uma arquitetura de jogo modular no Unity com ScriptableObjectse explica como ele usa padrões de design e modularidade em sua arquitetura de código.
Este é o primeiro de uma série de seis mini-guias criados para ajudar os desenvolvedores do Unity com a demonstração que acompanha o e-book. A demonstração é inspirada na mecânica clássica de jogos de fliperama com bolas e pás e mostra como o ScriptableObjects pode ajudá-lo a criar componentes testáveis, dimensionáveis e fáceis de projetar.
Juntos, o e-book, o projeto de demonstração e esses mini-guias fornecem as melhores práticas para o uso de padrões de design de programação com a classe ScriptableObject em seu projeto Unity. Essas dicas podem ajudá-lo a simplificar seu código, reduzir o uso de memória e promover a reutilização do código.
Essa série inclui os seguintes artigos:
Antes de mergulhar no projeto de demonstração ScriptableObject e nesta série de mini-guias, lembre-se de que, em sua essência, os padrões de design são apenas ideias. Elas não se aplicam a todas as situações. Essas técnicas podem ajudá-lo a aprender novas maneiras de trabalhar com Unity e ScriptableObjects.
Cada padrão tem prós e contras. Escolha apenas os que beneficiam significativamente seu projeto específico. Seus designers dependem muito do Unity Editor? Um padrão baseado em ScriptableObject pode ser uma boa opção para ajudá-los a colaborar com seus desenvolvedores.
Em última análise, a melhor arquitetura de código é aquela que se adapta ao seu projeto e à sua equipe.
O PaddleBallSO gira em torno do jogo clássico que deu origem aos videogames modernos, com dois jogadores, duas pás e uma bola.
A ênfase aqui está na infraestrutura e não na mecânica do jogo. Pense nisso como o "encanamento do jogo" - a base menos glamourosa, mas de importância vital, que mantém seu aplicativo em execução.
Este projeto se concentra em como os ScriptableObjects podem trabalhar nos bastidores para criar um aplicativo unificado. Use-os para criar sistemas de jogos versáteis que podem simplificar a manutenção do projeto e promover a reutilização do código. Você também pode usá-los para dados do jogador, gerenciamento do estado do jogo, comportamentos no jogo e muito mais.
O projeto PaddleBallSO é compatível com a versão mais recente do Unity Long Term Support (LTS), atualmente 2022 LTS. Ele incorpora o UI Toolkit para criar a interface do usuário em tempo de execução e o Input System para lidar com as entradas do usuário.
Localize e baixe o projeto no repositório do GitHub.
Carregue a Bootloader_scene ou ative a opção Load Bootstrap Scene on Play no menu GameSystems. Entre no modo Play para começar.
Embora não sejam específicos de ScriptableObjects, o projeto de demonstração usa algumas técnicas comuns para ajudar a iniciar o aplicativo de jogo em um estado consistente e previsível.
Um Scene Bootstrapper (ou bootloader) é um script de extensão do Editor responsável por configurar o estado inicial do jogo. Esse código de inicialização é separado da lógica do jogo e garante que todas as dependências sejam configuradas corretamente para os objetos na cena.
Para evitar problemas de dependência, o bootstrapper configura objetos, gerenciadores ou serviços essenciais do jogo quando uma cena é carregada.
Se o seu aplicativo Unity abranger várias cenas, o carregador de inicialização poderá forçar o carregamento de uma cena bootstrap específica, que é a primeira cena das configurações de compilação. Ao sair do modo Reproduzir, o Editor recarrega a cena anterior.
Outro componente na cena bootstrap, o Sequence Manager, pode instanciar Prefabs essenciais no carregamento da cena. Nesse projeto de demonstração específico, tudo o que é necessário para criar o jogo é um Prefab, incluindo uma câmera, SplashScreen, menus de interface do usuário e um SceneLoader.
Em seguida, o SceneLoader carrega (e descarrega) aditivamente todas as cenas de jogo conforme necessário. Na maioria dos casos, essas cenas são compostas principalmente de Prefabs.
Cenas do projeto
Cada nível de minijogo é uma cena separada do Unity e aparece em Build Settings. Desative o SceneBootstrapper no menu GameSystems se você quiser explorar essas cenas individuais.
Muitos projetos também incluem uma área de preparação para o menu principal após a cena do bootstrap. Esse projeto de demonstração simplificado omite uma cena do menu principal.
Use os menus Play e Pattern para testar o PaddleBallSO, que inclui:
- Demonstrações de padrões de projeto, ou exemplos de tamanho reduzido, que mostram técnicas específicas e ilustram cada padrão isoladamente
- Minijogos que combinam esses elementos em amostras funcionais e funcionais
A pasta Core contém partes da base de código que não são específicas do aplicativo, como os scripts de padrão básico, o gerenciamento de cenas e a lógica da interface do usuário. Essas são classes mais gerais que podem ser aplicadas a uma variedade de aplicativos.
O jogo de amostra recria uma simulação icônica de física 2D e mostra o potencial dos padrões de design baseados em ScriptableObject.
Antes de mergulhar nos padrões, no entanto, você deve se familiarizar com os MonoBehaviours que compõem o aplicativo. Como é de se esperar, componentes como os scripts Paddle, Ball, Bouncer e ScoreGoal regem a jogabilidade básica.
Vários scripts de gerenciador de nível superior controlam o fluxo do jogo:
- O GameManger controla os estados do jogo (início, fim, reinicialização), inicializa os componentes do jogo, gerencia a interface do usuário e responde a eventos.
- O GameSetup trabalha com o GameManager para configurar a bola, as pás, as paredes e os gols.
- O ScoreManager atualiza os valores de pontuação, lida com eventos do jogo e controla as atualizações da interface do usuário para exibições de pontuação.
Esses MonoBehaviours funcionam com seus ScriptableObjects. Eles desempenham um papel fundamental na ponte entre esses componentes para que possam conversar e compartilhar dados entre si.
Os eventos são fundamentais para a comunicação entre as diferentes partes do projeto. Eles conectam esses scripts de gerenciador a outros objetos de cena e à interface do usuário. Essa arquitetura orientada por eventos pode ajudar a tornar o código mais organizado e passível de depuração.
Também fornecemos exemplos de demonstração simplificados para cada um dos padrões mais comuns de ScriptableObject. À medida que você se familiarizar com eles, começará a reconhecer como os ScriptableObjects sustentam a arquitetura do minijogo.
Poderíamos ter criado o minijogo em destaque com muito menos linhas de código, mas esta demonstração se concentra especificamente nos padrões de design com ScriptableObjects. Observe que você também pode implementar muitos desses padrões sem ScriptableObjects.
Decida em equipe como cada padrão pode ser aplicado ao seu projeto e escolha a abordagem que funciona melhor para você.
A modularidade no desenvolvimento de software envolve a divisão de um aplicativo em partes menores e mais independentes. Esses módulos servem a propósitos específicos e podem ser desenvolvidos e testados separadamente.
Cada pequeno conjunto de objetos funciona como uma unidade e lida com um aspecto do jogo. Isso pode ser qualquer coisa, desde o controle da entrada do jogador, a manipulação da física ou o registro da pontuação.
Ao explorar os scripts do projeto, preste atenção aos seguintes pontos principais:
- Construa suas cenas a partir de Prefabs: Você notará que a maioria das cenas do projeto são simplesmente coleções de Prefabs com o mínimo de substituições. Os pré-fabricados oferecem inerentemente um nível de modularidade. A solução de problemas de um recurso se torna uma questão de testar esse Prefab específico isoladamente. Assim como os ScriptableObjects, os Prefabs são ativos em nível de projeto que podem ser reutilizados e compartilhados em várias cenas.
- Use ScriptableObjects para armazenamento de dados (e muito mais): Evite usar MonoBehaviours para armazenar dados estáticos de jogabilidade. Em vez disso, aproveite os ScriptableObjects para melhorar a reutilização. Você também pode relegar determinada lógica de jogo aos ScriptableObjects ou fazer com que eles facilitem a comunicação entre os objetos da cena.
- Preocupações separadas: Mantenha uma distinção clara entre dados, lógica e interface do usuário em seu projeto. Isso melhora a capacidade de manutenção do código e simplifica a depuração. Nosso sistema de tela de menu utiliza o mais novo UI Toolkit. Esse sistema de interface do usuário impõe um fluxo de trabalho que separa a interface de sua lógica subjacente. Para obter mais detalhes, consulte Design e implementação da interface do usuário no Unity livro eletrônico.
- Minimizar as dependências: A redução das dependências entre os componentes facilita a modificação ou a substituição de partes do seu projeto sem causar problemas imprevistos.
- Use eventos para comunicação: Os eventos possibilitam o acoplamento flexível entre os componentes, permitindo que eles enviem mensagens uns aos outros sem dependências diretas. Você pode dissociá-los ainda mais com "canais de eventos" baseados em ScriptableObject.
- Evite singletons desnecessários: Os padrões de projeto Singleton podem ser úteis, mas somente quando uma única instância de uma classe é essencial. O uso excessivo de singletons pode resultar em código fortemente acoplado e dificultar os testes. Ignore o singleton se ele não for necessário.
A refatoração de um script monolítico grande em partes menores promove a reutilização e o dimensionamento. Isso leva a uma melhor colaboração da equipe e a testes simplificados.
Criamos o projeto PaddleBallSO para demonstrar os casos de uso do ScriptableObject. Aqui estão alguns lugares específicos onde você os verá em ação:
- O ScriptableObject GameDataSO serve como um contêiner de dados central para as configurações do jogo. Edite seus dados comuns uma vez e depois compartilhe-os com os outros objetos que precisam deles.
- Os minijogos dependem de vários canais de eventos para se comunicarem de forma desacoplada. Esses eventos baseados em ScriptableObject formam a espinha dorsal de como os objetos enviam mensagens uns aos outros.
- A reprodução de som usa um objeto delegado baseado em ScriptableObject para separar a lógica do componente MonoBehaviour.
- Usamos um enum baseado em PlayerIDSO ScriptableObject para diferenciar "equipes" entre Player1 e Player2.
- O ScriptableObject LevelLayoutSO serve como um contêiner de dados para as posições iniciais dos elementos do jogo, como pás, gols, paredes e bola. Isso permite a modificação fácil de layouts de nível dentro do Unity e externamente por meio de arquivos JSON exportados. O modding de designs de níveis fora do Unity pode incentivar a criatividade dos jogadores e o compartilhamento de layouts personalizados.
Não deixe de conferir as demonstrações de padrões de design para ver alguns extras também!
Embora os ScriptableObjects possam ser uma ferramenta poderosa para armazenar dados de jogos e otimizar seu fluxo de trabalho, é essencial usá-los de forma eficaz para evitar a desorganização do projeto.
Aqui estão algumas práticas recomendadas para o uso de ScriptableObjects no Unity:
- Mantenha os dados modulares e organizados: Use ScriptableObjects separados para tipos de dados diferentes (por exemplo, um para estatísticas do jogador, outro para comportamento do inimigo etc.). Divida dados complexos em partes menores que possam ser facilmente gerenciadas.
- Use pastas e convenções de nomenclatura: Os ScriptableObjects podem ajudar a reduzir o código em seus scripts, mas a desvantagem é lidar com mais ativos nas pastas do projeto. A organização adequada de nomes e diretórios pode ajudar a gerenciar esses ScriptableObjects de forma eficiente. Consulte nosso guia de estilo de código para obter dicas sobre nomenclatura.
- Evite o uso excessivo de ScriptableObjects: Os ScriptableObjects são contêineres de dados incríveis, mas é importante não usá-los em excesso. Lembre-se de que os ScriptableObjects podem aumentar a complexidade do seu projeto, portanto, implemente-os somente quando oferecerem um benefício claro. (Por exemplo, não os use para salvar dados persistentes).
- Faça backup dos dados regularmente: As alterações nos ScriptableObjects ocorrem "ao vivo" no tempo de execução e são salvas como arquivos de ativos. Certifique-se de fazer backup de seu projeto regularmente para evitar a perda de dados. Use o software de controle de versão para acompanhar as alterações nos ScriptableObjects.
- Use a janela Inspector: Uma das principais vantagens dos ScriptableObjects é que eles são serializáveis e aparecem no Inspector. Aproveite a interface do Editor para visualizar e manipular dados armazenados em ScriptableObjects.
- Use os scripts personalizados do Editor a seu favor: Os ScriptableObjects não podem fazer referência nativa a objetos de tempo de execução da hierarquia de cenas. Use o script do Editor para tornar o Inspector uma interface mais fácil de usar se precisar visualizar esses objetos.
Seguindo essas diretrizes, você pode evitar armadilhas comuns de desenvolvimento.
Leia mais sobre padrões de design com ScriptableObjects no e-book Create modular game architecture in Unity with ScriptableObjects. Você também pode saber mais sobre os padrões comuns de design de desenvolvimento do Unity no e-book Level up your code with game programming patterns.