Limitações de jogos de 8 bits e sua recreação exata no Unity

imagem

Jogos retrô com mecânica simples e gráficos de pixel podem evocar memórias quentes de jogadores experientes e, ao mesmo tempo, são bastante acessíveis para um público mais jovem. Hoje, muitos jogos são chamados de retro, mas é necessário esforço e planejamento para criar um estilo nostálgico. Por isso, convidamos os caras do Mega Cat Studios para nos ajudar a discutir esse tópico. Nesta postagem, abordaremos tudo o que você precisa para criar gráficos autênticos no estilo de jogo NES, incluindo opções importantes do Unity, estruturas gráficas e paletas de cores.

Crie arte autêntica no estilo NES


Para começar, abordaremos o básico da criação de gráficos para jogos que atendem às limitações do clássico Nintendo Entertainment System. Essa geração de consoles impõe sérias restrições aos artistas que procuram reproduzir seus gráficos autênticos. Essas são restrições nas paletas usadas e no tamanho e número de objetos na tela. Além disso, é importante considerar que a resolução desse console é de 256 × 240 pixels.

Paletas


Ao criar gráficos compatíveis com NES, o artista deve considerar muitas limitações. Primeiro, a mais importante dessas limitações é como as paletas de cores são usadas na imagem. O NES é único, pois todas as cores possíveis da paleta são "conectadas" ao console. O NES escolhe quais cores usar na imagem enviando conjuntos de valores para a GPU do NES, após o que a GPU retorna as cores correspondentes a esses valores. A seguir, é apresentada uma imagem da paleta de cores NES:


Essas cores não podem ser alteradas porque fazem parte do próprio console. Todos os jogos da NES usam combinações dessas cores que compõem as imagens.

Sub paletas


Para criar combinações usadas em jogos, são criadas sub-paletas anexadas a sprites ou imagens de plano de fundo do jogo. O NES divide a paleta em subpaletas que podem ser atribuídas a sprites e planos de fundo. Cada sub-paleta contém uma cor comum, usada em todas as sub-paletas, e três cores exclusivas. Ele pode carregar quatro sub-paletas para planos de fundo e quatro sub-paletas para sprites. No caso de sprites, a cor geral no início de cada sub-paleta é considerada transparente.


Aqui está um exemplo de um conjunto de sub-paletas usadas no jogo. A parte superior mostra as sub-paletas de fundo, a parte inferior mostra as sub-paletas de sprites. Neste exemplo, preto é a cor comum usada em todas as sub-paletas. Como a cor geral é considerada transparente nos sprites, é necessária uma segunda cor preta nas sub-paletas dos sprites, que é usada como a cor visível.

Atribuindo sub-paletas


As restrições ao uso de paletas tornam-se ainda mais rigorosas quando o artista passa a usar as paletas no jogo. Para explicar isso, você precisa falar mais sobre como os consoles retrô armazenam e exibem gráficos. Os gráficos de qualquer console retro são armazenados dentro do jogo como blocos de 8 × 8 pixels. Graças a isso, os artistas podem economizar espaço reutilizando blocos para objetos diferentes. (Por exemplo, partes da estrada podem ser reutilizadas criando um penhasco ou construindo a partir delas). Também é importante que as informações de cores não sejam armazenadas com os gráficos. Todos os blocos são salvos em uma paleta monocromática. Graças a isso, quando um bloco é exibido no jogo, você pode atribuir uma sub-paleta a ele e exibi-lo simultaneamente na tela com diferentes sub-paletas. Isso é importante ao recriar gráficos de console retro em plataformas modernas, porque afeta a maneira como atribuímos paletas a gráficos.

O NES atribui paletas a sprites e planos de fundo de maneira diferente. Ela atribui paletas de sprites taylovo. Isso significa que, com cada bloco 8 × 8 no sprite, uma das quatro sub-paletas do sprite pode ser associada.


Esse personagem ninja usa duas sub-paletas para aumentar a profundidade da cor. À direita, você pode ver que está dividido em blocos 8 × 8 separados. Nessa forma dividida, é perceptível que o turquesa claro e o vermelho escuro usados ​​na espada e na bandana da cabeça são exclusivos desses ladrilhos, e os contornos roxo e preto escuros são usados ​​nos três ladrilhos restantes.

Os fundos estão sujeitos a restrições muito mais rigorosas. As paletas de fundo são atribuídas a fragmentos 16 × 16. As ligações da sub-paleta de plano de fundo da tela inteira são denominadas Tabelas de Atributos (tabelas de atributos). É justamente por causa dessas tabelas que a maioria das imagens retro usa ativamente segmentos de blocos repetidos. Esses segmentos geralmente consistem em 16 x 16 blocos, e é por isso que são colocados em tabelas de atributos. Apesar de isso ter sido causado por limitações de hardware, esses blocos de fundo 16 × 16 se tornaram a característica definidora dos gráficos retrô e agora são absolutamente necessários para sua reconstrução em jogos modernos.


Aqui está um exemplo do plano de fundo de uma bela cidade no estilo de RPG, feita levando em conta essas restrições. A imagem à direita mostra que está bem dividida em blocos de 16 × 16 pixels e paletas são definidas para cada bloco. Para economizar espaço, elementos como telhas, grama e tijolos na ponte são compostos de segmentos repetidos desses blocos. As telhas de edifícios pequenos usam as mesmas telhas, mas recebem sub-paletas diferentes, dando uma aparência única.

Sobreposição de Sprite


Embora os artistas possam usar subpaletas diferentes para cada bloco de sprite 8 × 8, eles podem ter uma situação em que é necessário dar ao sprite uma maior profundidade de cor. Nesse caso, você pode usar a sobreposição de sprite. Sobrepor sprites é a divisão de um sprite em dois sprites separados e os coloca um em cima do outro. Isso permite que os artistas contornem a condição de usar uma sub-paleta por bloco 8 × 8. Graças a isso, os artistas podem dobrar o número de cores que podem ser usadas em uma área 8 × 8. A única desvantagem séria dessa abordagem são as limitações da renderização de sprites. O NES é capaz de exibir apenas 64 blocos de sprite 8 × 8 por vez e apenas oito blocos de sprite em uma linha horizontal. Se esse limite for atingido, todos os outros blocos não serão renderizados na tela. É por isso que em muitos jogos para NES com um grande número de sprites na tela, eles começam a piscar. Nesse caso, a única maneira de exibir todos os sprites é mostrá-los em quadros alternados. Tais restrições devem ser levadas em consideração ao sobrepor camadas de sprites, porque isso duplica não apenas o número de cores, mas também o número de peças de sprite em uma linha horizontal.


Aqui está um exemplo de Sprite Layering em ação. A versão tricolor original do sprite pirata fantasma é mostrada à esquerda. O artista o dividiu em duas partes - o corpo / chapéu e o rosto / mãos, e depois atribuiu a eles paletas diferentes. À direita está o resultado da superposição de dois elementos um no outro.

Para contornar as limitações da tabela de atributos, você pode implementar camadas de sprite usando o plano de fundo. Esse truque geralmente é usado para imagens estáticas, como telas de plotagem e retratos de caracteres, o que lhes confere uma profundidade de cor muito maior. Para isso, o artista deve desenhar parte da imagem como plano de fundo e, em seguida, aplicar sprites sobre ela para preencher as partes restantes.


No retrato de um pirata fantasma, também são usadas camadas de sprites, dando-lhe uma maior profundidade. Seu crânio verde é exibido na tela como um sprite, e sua gola e chapéu fazem parte do plano de fundo. Isso permite que o artista use mais cores no segmento 16 × 16 para contornar completamente as limitações da tabela de atributos.

Bancos gráficos


Para explicar outra limitação importante do NES, primeiro precisamos voltar ao fato de que os gráficos são armazenados em blocos. Os blocos gráficos são armazenados em páginas de 256 blocos, e os blocos dessas páginas não podem ser carregados no VRAM em locais diferentes; portanto, fica difícil rapidamente combinar e misturar blocos de páginas diferentes. O console VRAM do NES é capaz de exibir 512 blocos simultaneamente. Além disso, ela divide as peças ao meio para sprites e planos de fundo. Isso significa que, ao mesmo tempo, o console pode exibir apenas 256 blocos de sprite e 256 blocos de plano de fundo. Se um artista deseja exibir uma grande variedade de sprites e elementos de fundo, essa restrição o impede muito.


Aqui está uma representação gráfica dos blocos de plano de fundo e sprite do jogo carregados na VRAM. O console armazena planos de fundo e sprites em páginas separadas.

Para contornar essa limitação, o NES usa um recurso que permite que um artista divida cada página em páginas parciais chamadas bancos. Portanto, embora o NES não possa carregar blocos individuais a partir de diferentes pontos de dados gráficos, ele é capaz de carregar partes separadas da página em momentos diferentes. Na maioria dos jogos, esses bancos têm 1 KB e 2 KB de tamanho. Um banco de 1 KB corresponde a uma quarta página, ou 64 blocos, e um banco de 2 KB corresponde a meia página, ou 128 blocos. O artista deve decidir se deseja reservar cada tipo de banco para elementos de sprites ou fundos, porque é necessário usar os dois tipos. Isso significa que é impossível ter bancos de 1 KB para sprites e fundos. Uma página deve usar bancos de 1 KB e a outra 2 KB. Como regra, a maioria dos jogos usa bancos de 1 KB para sprites e 2 KB para planos de fundo, porque os conjuntos de blocos de plano de fundo geralmente são mais estáticos e requerem menos variabilidade e substituições em tempo real.


A imagem enlatada que vimos acima. O lado esquerdo mostra fundos que usam bancos de 2 KB, ou seja, divididos ao meio, e o lado direito mostra sprites divididos em bancos de 1 KB. Cada banco pode ser substituído livremente em tempo real.

A utilidade dos bancos de 1K para sprites é bastante importante. Se o sprite de um personagem tiver um grande número de animações que não couberem em uma página e, ao mesmo tempo, for necessário carregar outros sprites, as ações individuais poderão ser baixadas para bancos de 1 KB e substituídas por eles, dependendo do que está acontecendo na tela. Também aumenta a variabilidade de sprites que podem ser usados ​​em uma área do jogo. Por exemplo, se um jogador precisa encontrar seis tipos de inimigos no nível do jogo, mas apenas o jogador e três outros tipos de sprites são colocados na página do sprite, quando um tipo de inimigo desaparece da tela, o jogo pode substituir um dos bancos inimigos por um novo tipo de inimigo.

Uma das poucas desvantagens sérias do uso de bancos de 1 KB para sprites e 2 KB para planos de fundo é a maneira como o console NES processa a animação em segundo plano. Para animar um elemento de plano de fundo de um jogo para o NES, um artista deve criar bancos duplicados de elementos de plano de fundo animados. Cada novo banco duplicado conterá o próximo quadro de animação para cada um dos elementos animados. Esses bancos se substituem, criando animação. Se um artista usa bancos de meia página como pano de fundo, o armazenamento de todos esses bancos duplicados pode exigir muito espaço. Uma maneira de contornar essa limitação é colocar todos os elementos de fundo animados de todo o jogo em um banco. Mas o artista se depara com outra limitação: ele tem apenas 128 peças restantes para os elementos estáticos de cada plano de fundo. Cada artista decide qual método de armazenamento é melhor para ele.

Truques de camada


Muitos jogos daquela época usavam truques para criar efeitos como rolagem de fundo de paralaxe, mas também representam um desafio para artistas e designers. Consoles posteriores de 16 bits tinham suporte para várias camadas de segundo plano, mas o NES não tinha esse recurso. Todos os fundos eram uma única imagem plana. Para criar uma sensação de profundidade e de camadas, vários truques de programa foram usados. Por exemplo, para criar rolagem de paralaxe, os desenvolvedores poderiam definir um registro que informava quando uma determinada linha horizontal (chamada linha de varredura) era desenhada na tela.

Eles poderiam usar esse registro para controlar a velocidade e a direção da rolagem da tela. Graças a isso, você pode criar uma linha de plano de fundo horizontal, que rola a uma velocidade diferente do restante do plano de fundo. Para artistas e designers, o truque era ter em mente que o fundo ainda é uma imagem plana. Se uma plataforma ou qualquer outro elemento que deveria estar “na frente” de um fundo em movimento lento for colocado nessa área, ele também rolará mais lentamente do que o restante da imagem. Isso significa que os designers tiveram que organizar os elementos de segundo plano na cena para que o efeito não fosse distorcido.


Neste exemplo, a área destacada em vermelho para simular a profundidade pode ser feita para rolar mais lentamente do que o resto do plano de fundo. A interface na parte superior da tela não rola, embora também faça parte de uma imagem de plano de fundo plana.

Há mais um truque, graças ao qual os artistas podem "mover" um dos elementos de fundo para a frente. Na NES, os desenvolvedores podem fazer com que a prioridade do sprite seja menor que zero. Se isso for feito, o sprite será exibido em todos os pixels opacos do plano de fundo. As prioridades do sprite também podem ser alteradas e ativadas rapidamente, devido a que elementos individuais podem, se necessário, alterar a prioridade do sprite.

Fluxos de trabalho do Unity para a melhor sensação retrô


Faça o download de um projeto de exemplo e comece a trabalhar conosco!

A Mega Cat Studios de Pittsburgh, PA, transformou a criação de jogos retrô em uma forma de arte. De fato, alguns de seus jogos podem até ser comprados em cartuchos e reproduzidos em consoles retrô, como o Sega Genesis.



Pequena Medusa e Crise do Café

Mudanças recentes nos fluxos de trabalho do Unity transformaram o mecanismo em um ambiente muito adequado para a criação de jogos retrô. O Tilemap 2D foi aprimorado e agora suporta cartões de peças de peças retangulares, hexagonais e isométricas! Além disso, você pode usar o novo componente Pixel Perfect Camera para obter movimentos holísticos pixel a pixel e efeitos gráficos. Você pode até usar a pilha de pós-processamento para adicionar todos os tipos de belos efeitos retrô da tela. No entanto, antes de fazer tudo isso, você deve importar e configurar corretamente os ativos.

Preparação de ativos de sprite


Para que os ativos sejam limpos e pixelizados, eles devem primeiro ser configurados corretamente. Selecione cada um dos ativos que você está usando na janela Projeto e altere os seguintes parâmetros no inspetor:

  • Mude o modo de filtro para "Ponto"
  • Alteração de compactação para "Nenhum"


Outros modos de filtragem resultam em um leve desfoque da imagem, o que viola o estilo de pixel claro que estamos buscando. Ao usar a Compressão, os dados da imagem são compactados, resultando em uma ligeira diminuição na precisão. É importante considerar, porque alguns pixels podem mudar de cor devido à compactação, potencialmente alterando toda a paleta de cores.

Quanto menor o tamanho e o número de cores no sprite, maior será a compactação. Aqui está um exemplo de comparação da compactação normal (padrão) e falta de compactação.


Compactação normal / Imagem sem compactação - parece exatamente igual ao original

Outro aspecto a considerar é o parâmetro Tamanho máximo da imagem no Inspetor. Se a imagem do sprite for maior em qualquer eixo que a propriedade Tamanho máximo (por padrão, é 2048), ela será ajustada automaticamente para o tamanho máximo. Isso geralmente resulta em perda de qualidade e a imagem começa a ficar embaçada. Como algumas plataformas não podem suportar texturas maiores que 2048 em qualquer eixo, é melhor permanecer dentro desse intervalo.


O tamanho máximo é 2048 / E agora o tamanho máximo é 4096

A imagem acima mostra um sprite de uma folha de sprite (folha de sprite) com um tamanho de eixo único de 2208 e um tamanho máximo de 2048. Como você pode ver, aumentando a propriedade Tamanho máximo para 4096, conseguimos garantir o tamanho correto da imagem sem perda de qualidade.

Por fim, ao preparar uma sprite ou folha de sprite, você deve definir o parâmetro do modo da unidade dinâmica como Pixels, em vez de Normalizado.


Por esse motivo, o ponto de articulação da imagem será determinado com base em pixels, e não em um intervalo suave de 0 a 1 ao longo de cada eixo da imagem. Se o ponto de ancoragem do sprite não estiver alinhado com precisão ao pixel, perderemos a localização do sprite na precisão do pixel. Os pontos de ancoragem para sprites podem ser definidos no Editor de Sprites, que é aberto no Inspetor quando o ativo de sprite é selecionado.


Instalando o pacote Pixel Perfect 2D


Depois de preparar os ativos, podemos tornar o pixel da câmera perfeito. O resultado com precisão de pixels ficará claro e pronunciado. Sinais de pixel art imprecisos se tornam borrão (distorção) e a retangularidade de alguns pixels.

Um pacote 2D Pixel Perfect pode ser importado usando o Gerenciador de Pacotes do mecanismo Unity. Clique no menu Janela na barra de ferramentas e selecione Gerenciador de Pacotes. Na nova janela, clique em Avançado e marque a caixa de seleção Mostrar pacotes de visualização. Selecione 2D Pixel Perfect na lista à esquerda e clique em Instalar no canto superior direito da janela.


Isso é tudo. Agora você está pronto para começar a usar o componente de câmera com precisão de pixels.

Alta Precisão de Pixel


O componente Pixel Perfect Camera é adicionado ao componente Camera do mecanismo Unity e o complementa. Para adicioná-lo, vá para a câmera principal e adicione o componente Pixel Perfect Camera. Se o componente Pixel Perfect Camera não estiver no menu, siga as etapas acima para importá-lo para o projeto.


Agora vamos examinar as opções disponíveis.


Primeiro, recomendo ativar o modo de execução no modo de edição e definir a proporção para "Aspecto livre" na janela do jogo para que você possa alterar livremente a janela do jogo. O componente exibirá mensagens úteis na janela do jogo, indicando se a exibição tem precisão de pixels na resolução atual.


Agora você pode passar por cada parâmetro e ver como eles afetam a aparência do jogo.

  • Assets Pixels Per Unit — , . , , (pixels per unit, PPU), . , 16 16 , PPU 16 — 1. PPU.
  • Reference Resolution — . . -, . , Sega Genesis 320×224. Sega Genesis 320×224. , 16:9 320×180 398×224 ( ).
  • Upscale Render Texture — . , , - . «Upscale Render Texture» .


1. ( ) 2. Upscale Render Texture ( 45 , , ) 3. Upscale Render Texture ( 45 , , , .)

  • Pixel Snapping ( Upscale Render Texture) — (sprite renderer) , PPU. , transform . - , - .
    • Um exemplo:


Pixel Snapping . (0, 0), — (1.075, 0). . , . Pixel Snapping . — (0, 0), (1.075, 0). .

  • Crop Frame (X Y) — , , , .
  • Preenchimento estendido - sempre disponível se você ativar x e y para o Quadro de corte. Esta opção faz com que a câmera dimensione a janela do jogo para caber na tela enquanto mantém a proporção. Como a escala é realizada não apenas para múltiplos inteiros da resolução de referência, em todos os outros casos a precisão do pixel será perdida. No entanto, a vantagem desse parâmetro é que, apesar da perda de precisão dos pixels em muitas resoluções, não haverá barras pretas nas bordas e a tela estará completamente cheia. Embora o preenchimento de extensão geralmente cause desfoque, um aviso normal não é exibido.


Caráter e plano de fundo, preenchimento de estiramento embaçado

Recomendações da câmera Perfect Pixel


Se você precisar de uma exibição precisa de pixels com um snap na grade, recomendo o seguinte:

  • , ( 320×180).
  • Upscale Render Texture
    • , , 90, 180 270 , .
    • Upscale Render Texture - ; . , Pixel Perfect Camera Run in Edit Mode , . - , - .
  • Pixel Snapping
    • . , .
  • Crop Frame X / Y, Upscale Render Texture
    • - upscale render texture, X / Y - , .
  • Stretch Fill

Recomendamos configurar a câmera para que ela seja otimizada para uma proporção de tela de 16: 9, incluindo resolução de referência, se possível. No momento da redação deste artigo, a maioria dos jogadores reproduz monitores com uma proporção de 16: 9 e uma resolução de 1920 × 1080. Por exemplo, a resolução de referência de 320 × 180 possui uma proporção de 16: 9 e, portanto, com uma resolução de 1920 × 1080 e outras resoluções que são múltiplas de 320 × 180, por exemplo, 1280 × 720, não haverá bordas pretas nas bordas da tela.

Na barra de ferramentas do Unity, você pode ir para Editar> Configurações do projeto> Player e limitar as proporções suportadas pelo jogo. Se você achar que uma determinada configuração parece boa na proporção necessária, mas não se encaixa bem nas proporções individuais, aqui você pode desativar essas proporções. No entanto, lembre-se de que nem todos os usuários terão uma tela que seja bem compatível com suas limitações, portanto, isso não é recomendado. Em vez disso, use o corte para que esses usuários exibam bordas pretas e o jogo não inicie em uma resolução que não corresponda à tela.

Conclusão


Ao tentar criar um projeto autêntico para um console retro, é necessário considerar muitos aspectos técnicos que ninguém pensa no desenvolvimento moderno. Devido às peculiaridades de renderizar imagens e trabalhar com uma pequena quantidade de memória de máquinas antigas, os designers tiveram que pensar de forma criativa e contornar as limitações de hardware. Na era moderna, precisamos conhecer essas limitações e técnicas para recriar com precisão a aparência e o design dos jogos daquela época. No próximo post, veremos as limitações de design da era dos jogos de 16 bits, bem como o fluxo de trabalho do Unity necessário para recriar o estilo real da "TV antiga".

Source: https://habr.com/ru/post/pt462843/


All Articles