Como criar cenas e prefabs com foco no controle de versão

O objetivo deste guia é fornecer práticas recomendadas para criação de conteúdo no Unity que funcione com controle de versão. Para obter mais informações sobre o uso do controle de versão, confira o blog da Unity sobre controle de versão para uma colaboração mais forte ou o e-book mais aprofundado Melhores práticas para controle de versão . Embora ambos os recursos contenham boas informações gerais para trabalhar com controle de versão, o foco deste blog é como o conteúdo se integra ao controle de versão e como evitar conflitos de mesclagem quando muitos criadores estão trabalhando no mesmo conteúdo ou em conteúdo adjacente ao mesmo tempo.
Há muita confusão online sobre arquivos .meta e controle de versão. Arquivos .meta devem sempre ser verificados no controle de versão. Eles contêm informações importantes, como o GUID do arquivo que conecta todas as referências entre ativos. Eles devem ser mantidos sincronizados com seus arquivos de origem (tanto o nome quanto o local devem sempre corresponder ao arquivo de origem associado). Nunca mova ou renomeie um arquivo de ativo fora do Editor Unity, a menos que ferramentas específicas tenham sido criadas para essa finalidade ou a funcionalidade dos arquivos .meta seja completamente compreendida.
O modo de arquivo .meta de controle de versão padrão é Arquivos Visíveis, que mostra os arquivos .meta no disco no sistema operacional, em vez de ocultá-los. Se você estiver usando o Perforce, selecione o modo Perforce.
A primeira coisa que qualquer equipe deve fazer ao trabalhar com Unity e controle de versão é configurar o Smart Merge. Por padrão, o Unity armazena arquivos YAML como texto, o que os torna mescláveis no controle de versão. Alterar o Modo de Serialização de Ativos para binário removerá a capacidade de mesclar esses arquivos pelo controle de versão.
Como os arquivos YAML do Unity são baseados em texto, muitos softwares de mesclagem de controle de versão tentarão mesclá-los usando texto ou regras de codificação. O Smart Merge foi criado pela Unity para mesclar tendo em mente a estrutura YAML. Recomendamos impor o uso do Smart Merge como a ferramenta de mesclagem padrão para todos os arquivos YAML.
O Smart Merge reduzirá muito a quantidade de trabalho perdido devido a conflitos de mesclagem, mas se sua equipe tiver tolerância zero para possíveis perdas de trabalho, recomendamos também usar o bloqueio de arquivo e impor a resolução manual de conflitos de mesclagem para quaisquer arquivos YAML.
O bloqueio de arquivos é uma prática comum em grandes estúdios, onde vários criadores de conteúdo podem trabalhar no mesmo arquivo binário (ou arquivo YAML) ao mesmo tempo. O controle de versão do Unity impede que qualquer pessoa faça check-out de um arquivo bloqueado. Impede forçosamente que qualquer pessoa envie um arquivo bloqueado.
O Git requer que o Git LFS seja inicializado para dar suporte ao bloqueio de arquivos. Recomendamos usar o Git LFS para qualquer projeto que tenha arquivos de conteúdo grandes e use o Git para controle de versão.
Equipes bem-sucedidas geralmente têm diretrizes rígidas em relação a convenções de nomenclatura, estruturas de pastas, onde os ativos devem ser localizados e como os ativos devem ser editados. Como cada equipe é diferente, não há um conjunto de diretrizes universais. O mais importante é escolher o sistema certo para sua equipe e mantê-lo enquanto ele funcionar.
Diretrizes específicas e rígidas simplificam o desenvolvimento de ferramentas para verificação de conteúdo. Isso evita bugs antes mesmo que eles entrem no jogo. Validar conteúdo com código e ferramentas se torna muito mais fácil com clareza na localização e nomenclatura dos ativos. Você pode então aplicar mais facilmente os padrões de importação do Unity por meio do Pós-processamento de ativos e predefinições.
Ao criar conteúdo, é importante utilizar os princípios de separação de preocupações . Pensar em como o conteúdo deve ser dividido e onde ele deve ficar manterá o projeto limpo e evitará que a maioria dos criadores de conteúdo tenha conflitos de mesclagem. Ele também pode ajudar na descoberta e integração de especialistas em recursos, onde recursos individuais ficam em subcenas ou Prefabs específicos. Os principais blocos de construção que podem ser usados para separar conteúdo em arquivos são Cenas, Prefabse Subgráficos.


Cenas são os blocos de construção macro para qualquer aplicativo Unity. Cada cena é serializada (salva) em um arquivo, o que significa que elas podem ser usadas para organizar o conteúdo de uma forma amigável para controle de origem e edição simultânea. O Carregamento Aditivo de Cena é frequentemente usado de forma eficaz para criar cenas muito grandes, conteúdo de streaming ou até mesmo cenas muito simples que têm vários componentes com preocupações separadas.
Em geral, recomendamos armazenar dados dependentes de cena em cenas. Por exemplo, no caso de iluminação assada, luzes, mapas de luz e configurações de ambiente, tudo depende da cena em que estão. Quase todo o resto pode ser armazenado em Prefabs. Se uma cena for pequena e tiver conteúdo específico que só será editado naquela cena, pode fazer sentido armazenar todos esses dados em uma única cena. Entretanto, é importante observar que se houver dois GameObjects em uma cena, qualquer alteração em um desses objetos resultará em alterações no arquivo de cena.
Embora o Smart Merge deva lidar com o cenário em que dois criadores de conteúdo alteram dois objetos diferentes na cena ao mesmo tempo, alterações mais elaboradas podem resultar em conflitos insolúveis. Recomendamos utilizar Prefabs para ajudar a mitigar esse problema.
Em termos de estrutura de cena explícita, a demonstração do Unity Netcode contém um fluxograma útil de um layout de cena padrão para um projeto simples, semelhante aos que vimos em muitos cenários.
Prefabs podem ser usados para criar conteúdo modular e separado. Para mais informações, confira este tutorial sobre Prefabs e Prefabs Aninhados. A seção mais importante desse tutorial é a seção Melhores Práticas . Não há regras explícitas sobre a criação de conteúdo com Prefabs. Cada equipe terá que decidir o que funciona melhor para ela com base em seu projeto. No entanto, existem algumas boas diretrizes a serem seguidas:
- Pense nos pré-fabricados como os blocos de construção da sua casa ou projeto. Geralmente, há uma raiz pré-fabricada que representa a fundação da casa. Dentro dela estão os pré-fabricados para cada componente reutilizável que compõe o restante da casa. Elas podem ser tão granulares quanto um peitoril de janela ou tão largas quanto uma parede com janelas. O nível de granularidade necessário dependerá de como os criadores de conteúdo desejam editar seus Prefabs.
- Os prefabs podem ser aninhados. Isso significa que no exemplo acima, pode haver uma casa pré-fabricada, com paredes, telhados, janelas e portas pré-fabricadas que compõem a casa. Uma coisa importante a ser observada sobre o aninhamento de Prefabs é que quanto mais profunda for a hierarquia, maior será a probabilidade de o projeto encontrar problemas de desempenho. Geralmente, recomendamos manter as hierarquias do Prefab abaixo de 5 a 7 níveis de profundidade.
- Ao aninhar Prefabs, geralmente é uma boa ideia editá-los no Modo Prefab. Isso garante que as propriedades ou substituições do Prefab sejam definidas no local correto. Editar propriedades do Prefab na visualização da cena pode resultar em substituições residindo no Prefab errado ou na própria cena. Isso pode ter consequências indesejadas e causar conflitos de mesclagem. Às vezes, é necessário substituir uma propriedade Prefab filho em um Prefab pai (variações podem ser obtidas dessa forma sem afetar todas as referências a um Prefab específico). Este é um fluxo de trabalho padrão, mas é importante ter cuidado ao fazer alterações e aplicar substituições no Prefab ou cena apropriados.
- Tudo em um Prefab será carregado e instanciado na memória em tempo de execução quando um Prefab for carregado e instanciado. Isso significa que se efeitos visuais ou objetos anexados que nem sempre estão presentes estiverem dentro de um Prefab, esses objetos serão instanciados na memória. Isso pode resultar em inchaço de memória, pois cada Prefab instanciado instanciará tudo dentro dele. Se os objetos tiverem efeitos visuais ou modelos ocasionais anexados a eles, é melhor ter um sistema de pool e um gerenciador de anexos que adicione esses componentes em tempo de execução. Qualquer coisa em um sistema de pooling geralmente não deve ser colocada dentro de um pré-fabricado.
- Nem tudo precisa ser um Prefab. Blocos de construção menores podem ser GameObjects dentro de um Prefab ou até mesmo uma cena. Se um objeto for exclusivo de uma cena ou Prefab, não há necessidade de criar um Prefab para ele.
- Variantes pré-fabricadas devem ser usadas com cuidado. Geralmente, o melhor uso de uma variante Prefab é quando os blocos de construção principais de um objeto são idênticos, com apenas diferenças simples. Por exemplo, pode ser útil usar uma variante Prefab para um componente de jogo que tenha funcionalidades idênticas, mas visuais diferentes. Nesse cenário, alterar a funcionalidade principal afetará a funcionalidade do Prefab e de suas variantes, mas o visual permanecerá substituído. Tenha cuidado ao criar variantes excessivamente complexas do Prefab, pois alterações no Prefab raiz podem ter consequências indesejadas no Prefab substituído. Como regra geral, algo como um sistema de variação de personagem ou qualquer outro sistema complexo de skinning visual não deve ser baseado em variantes do Prefab, a menos que o sistema seja muito simples.
Recomendamos criar uma estratégia consistente para determinar o que deve ser Prefabs e o que deve ser GameObjects dentro de Prefabs ou cenas.
Se um Prefab for criado diretamente de um arquivo FBX, um tipo especial de Prefab chamado Prefab modelo será criado. O resultado é uma variante Prefab do arquivo FBX. Quaisquer adições ou alterações serão armazenadas como substituições no arquivo Prefab. Entretanto, como a maioria dos dados é armazenada no arquivo FBX, alterações e adições ao Prefab não podem ser aplicadas aos Prefabs do modelo. Se você estiver usando o fluxo de trabalho da variante do modelo Prefab, é importante manter as alterações estruturais no mínimo.

Existem dois fluxos de trabalho alternativos que permitem estruturas menos fortemente acopladas entre o modelo FBX e o Prefab:
Adicionar o arquivo FBX diretamente em uma cena e então adicionar componentes ou modificações estruturais em GameObjects na cena. Neste cenário, todas as alterações agora são armazenadas no arquivo de cena. Isso pode resultar em conflitos de mesclagem se muitas pessoas estiverem usando esse fluxo de trabalho na mesma cena. Recomendamos esse fluxo de trabalho somente se as alterações tiverem que permanecer na cena e os conflitos não forem um problema.
Criando um Unity Prefab padrão a partir do modelo explodido. Neste método, o modelo FBX é arrastado para a cena e então descompactado completamente. Isso é então usado para criar um Prefab. Essa metodologia desvincula completamente o arquivo FBX do Prefab. Isso é útil se for desejado um acoplamento muito flexível entre o arquivo FBX e o Prefab. Ele não herdará mais nenhuma alteração estrutural feita no arquivo FBX original. O acoplamento será apenas entre os nomes das malhas, materiais e animações. Todo o resto residirá no próprio arquivo Prefab. Isso pode ser útil para criar variantes totalmente exclusivas de um modelo FBX. Por exemplo, se dois personagens usam o mesmo modelo, mas precisam de malhas, materiais ou até mesmo hierarquias completamente diferentes, essa metodologia pode ser melhor do que criar vários arquivos FBX que ocupam memória e espaço em disco extras. Uma coisa a ser observada com esse método é que quando um nome de malha ou material muda no arquivo FBX original, o objeto não desaparece, mas, em vez disso, faz referência a uma malha ou material ausente. Isso pode ser útil quando são necessárias configurações de componentes extremamente complexas. Em vez de fazer o GameObject desaparecer e perder todos os componentes, o objeto permanece e os componentes podem ser transferidos para o novo objeto, ou a malha ou o material renomeado pode ser encaixado de volta no GameObject que agora está referenciando uma malha ou material ausente.
Nas duas imagens abaixo, alterações são feitas em um arquivo FBX e depois reimportadas. O círculo ao redor do logotipo da Unity na bola foi excluído. O suporte principal é renomeado. O material da bola principal muda de preto para verde e um novo modelo é introduzido acima do logotipo do suporte com transformações que o elevam acima do modelo.

Tudo isso está intimamente relacionado tanto no arquivo FBX quanto no modelo Prefab. No Prefab não modelo, a hierarquia, os nomes e os materiais originais são mantidos. A malha excluída agora é uma malha ausente, mas o GameObject ainda está presente. A malha renomeada também não está visível porque está fazendo referência a um nome de malha que não existe mais no modelo. O material alterado não é atualizado porque o GameObject ainda está referenciando o material original. Além disso, a mudança de hierarquia não é respeitada e a malha permanece no mesmo lugar porque seu pai não mudou.

Nas imagens de antes e depois abaixo, os resultados das alterações feitas acima são exibidos na hierarquia da cena. O arquivo FBX referenciado diretamente na cena e o modelo padrão Prefab respondem a quaisquer alterações feitas no arquivo FBX original. O Prefab descompactado mantém sua hierarquia original e não responde a exclusões ou alterações de nome.

É importante tomar decisões cuidadosas sobre qual metodologia será usada em um determinado cenário. Se for desejado um acoplamento forte entre o Editor e os arquivos FBX, então o modelo padrão Prefab é provavelmente a melhor escolha. Se for desejado um acoplamento muito flexível (por exemplo, um sistema de caracteres muito flexível, onde malhas ou materiais podem ser trocados com frequência), criar Prefabs não-modelo com referências suaves aos componentes do arquivo FBX funcionará melhor.
No caso de ferramentas gráficas como Shader Graph ou Visual Effect Graph, os subgráficos Shader Graph e os subgráficos Visual Effect Graph podem ser usados para criar nós funcionais reutilizáveis que ficam em um arquivo separado e podem ser editados sem causar conflitos em cada Shader Graph ou Visual Effect Graph. Isso permite que os usuários separem preocupações de maneira semelhante aos Prefabs e cenas. Recomendamos criar uma estratégia de reutilização aproveitando os subgráficos onde isso fizer mais sentido.

Evitar hierarquias profundas é uma afirmação universal para conteúdo relacionado a Cenas, Prefabs, GameObjects, Animação, UI e qualquer outra coisa. Em geral, hierarquias profundas de qualquer tipo tendem a resultar em problemas de desempenho. Hierarquias de animação profundas em personagens farão com que menos personagens possam ser desenhados na tela devido a problemas de desempenho da CPU. Por isso, recomendamos colocar todas as hierarquias animadas no nó raiz da cena para ajudar no desempenho. Optar por hierarquias planas ao usar UGUI e Canvas resultará em melhor desempenho devido a menos atualizações de layout em cascata. Prefabs profundamente aninhados podem causar problemas de desempenho e também gerar confusão quando as substituições não são gerenciadas com cuidado.
Frequentemente vemos equipes armazenando conteúdo de origem em vários locais, desde unidades de rede até máquinas locais. Recomendamos colocar todo o conteúdo de origem importante no controle de versão de uma forma ou de outra.
O método mais comum que vemos é colocar o conteúdo de origem em uma pasta no controle de versão que está fora da pasta Assets. Isso garante que o Unity não tente importar nenhum conteúdo diretamente dos arquivos de origem. Arquivos do Maya, 3ds Max, Blender e Photoshop serão importados automaticamente para modelos e texturas se forem colocados em qualquer lugar na pasta de ativos. Embora a Unity suporte isso, não recomendamos essa prática. Além disso, recomendamos espelhar o diretório de origem para o conteúdo do diretório de ativos para que o rastreamento de ativos seja relativamente fácil.
O conteúdo de origem deve ser mascarável para os usuários, pois a maioria deles não precisará de tudo e o conteúdo de origem pode ser extremamente grande no disco (pense em terabytes). Em alguns softwares de controle de versão, criar máscaras de conteúdo é bastante simples. No controle de versão do Unity, isso é obtido com arquivos camuflados. No Perforce, as visualizações são usadas para mascarar conteúdo do cliente. O Git, no entanto, não foi projetado para funcionar dessa maneira. Por isso, recomendamos criar um repositório Git separado para o conteúdo de origem ou um repositório separado para cada tipo de conteúdo (por exemplo, artistas 3D podem nunca precisar sincronizar a fonte de áudio completa e vice-versa).
Criar conteúdo que funcione com controle de versão e ofereça suporte a vários usuários trabalhando nas mesmas áreas é uma tarefa difícil. No entanto, o Unity fornece blocos de construção que podem ser usados com planejamento e reflexão cuidadosos para criar conteúdo em larga escala que não resulte em conflitos de mesclagem insolúveis ou perda de trabalho.