[POO] Herança na Unity

Herança é um conceito do paradigma de programação conhecido como Programação Orientada a Objetos , que tem como objetivo construir e trabalhar com abstrações de objetos do mundo real, em um nível de código. A Herança dá a capacidade de uma classe/objeto herdar comportamentos previamente definidos em outra classe, sem a necessidade de duplicação do código, permitindo a extensão e a sobrescrita de comportamentos já existentes, de acordo com a necessidade do novo objeto/classe. Para definir uma relação de herança no C#, a "palavra" reservada : (dois pontos) deve ser utilizada na definição da classe que estamos criando, indicando de qual outra classe o nosso script deve herdar. public class Jogador : MonoBehaviour { // Classe Jogador que herda da classe MonoBehaviour } Por padrão, todos os scripts criados na Unity herdam de MonoBehaviour, que é a classe base da Unity para Scripts que serão associados aos GameObjects do jogo. Embora essa definição de herança

Iluminação 2D com Universal Render Pipeline

E aí, galera! Nesse post nós vamos desenvolver um projeto utilizando o Universal Render Pipeline da Unity, também conhecido como Universal RP para aproveitar algumas das novas funcionalidades de iluminação para jogos 2D.

Durante o este post vamos utilizar um exemplo de jogo de dungeon, cujo cenário possui uma iluminação reduzida, e o personagem possui uma iluminação adicional ao seu redor, como pode ser visto logo abaixo:

Resultado final esperado para o exemplo desenvolvido
Resultado final esperado para o exemplo desenvolvido

O projeto desenvolvido neste post utiliza o conjunto de assets chamado A Blocky Dungeon, desenvolvido por Buch e disponível para download no OpenGameArt.org.

O projeto desenvolvido neste post pode ser baixado aqui.

Inicialmente, o nosso projeto não possui nenhuma luz configurada. Para utilizar Luz 2D na Unity, precisamos habilitar o novo pacote de componentes de renderização (Universal RP) da Unity, através do Package Manager. Para abrir a janela do Package Manager basta acessar a opção Windows no menu superior da Unity e em seguida selecionar a opção Package Manager.

Abrindo o Package Manager
Abrindo o Package Manager

Após abrir o Package Manager precisamos acessar a seção dos pacotes do Unity Registry e em seguida utilizar a barra de busca para encontrar o pacote Universal RP. Ao encontrar o Universal RP, basta clicar em instalar (install), como por ser visto a seguir:

Instalando o Universal Render Pipeline
Instalando o Universal Render Pipeline

Obs: Este post foi desenvolvido utilizar a Unity 2020.1.6f. O Universal Render Pipeline (Universal RP) substituiu o Lightweight RP a partir da versão 2019.3. Ou seja, em versões anteriores o Universal RP era conhecido como Lightweight RP.

Agora que temos o pacote Universal Render Pipeline instalado, podemos configurar o nosso jogo para utilizar uma renderização que suporte iluminação 2D. Pronto para continuar?

Configurando o Render Pipeline 2D

O Universal RP é um novo modelo de renderização que pode ser utilizado tanto em jogos 2D, quanto em jogos 3D. Por isso, precisamos informar para a Unity qual tipo de renderização queremos utilizar, e isso pode ser feito através da configuração do Render Pipeline.
Nossos próximos passos serão os seguintes:
  1. Criar um Pipeline Asset;
  2. Criar um 2D renderer;
  3. Configurar o projeto para utilizar o nosso Pipeline Asset e o 2D renderer.

Criando um Pipeline Asset

O Pipeline Asset é um arquivo de configuração da Unity que controle diversas funcionalidades gráficas e configurações de qualidade de jogo. Por enquanto, tudo o que precisamos saber sobre ele, é que é um requisito para utilizarmos iluminação 2D em nosso projeto. Ok?

Então, vamos criar o nosso Pipeline Asset a partir da nossa aba Project na Unity, clicando com o botão direito do mouse e selecionando a opção: Create -> Rendering -> Universal Render Pipeline -> Pipeline Asset (Forward Renderer).

Criando o Pipeline Asset
Criando o Pipeline Asset

Ao criar o Pipeline Asset (Forward Renderer), dois novos arquivos aparecerão em nosso projeto: UniversalRenderPipelineAsset e UniversalRenderPipelineAsset_Renderer.

UniversalRenderPipelineAsset funciona como um arquivo de configuração da Unity para o novo modo de renderização. Já o UniversalRenderPipelineAsset_Renderer, define como deve funciona a renderização utilizando o método Forward Renderer, adequado para jogos 3D. Por estarmos trabalhando com um jogo 2D, não precisamos o arquivo UniversalRenderPipelineAsset_Renderer, dessa forma, podemos deletá-lo sem risco para o nosso projeto.

Se observarmos as propriedades do UniversalRenderPipelineAsset no Inspector após deletarmos o UniversalRenderPipelineAsset_Renderer, poderemos notar que a configuração Scriptable Renderer Data não está definida (missing).
Propriedades do Pipeline Asset
Propriedades do Pipeline Asset

Para preencher essa opção, precisamos partir para o segundo passo da nossa lista e criar um 2D Renderer compatível com o Universal Render Pipeline. Isso pode ser feito através da opção: Create -> Rendering -> Universal Render Pipeline -> 2D Renderer (Experimental).

Criando o 2D Renderer
Criando o 2D Renderer

Vamos chamar nosso 2D Renderer de 2D Renderer Data, conforme visto acima. Em seguida, precisamos associar o 2D Renderer Data ao UniversalRenderPipelineAsset, conforme pode ser visto abaixo:
Associando o 2D Renderer ao Pipeline Asset
Associando o 2D Renderer ao Pipeline Asset

Com isso, concluímos os três passos de configuração do Render Pipeline 2D. Estamos prontos para utilizar o Render Pipeline 2D. O que achou?!

... como assim, pronto? Nada mudou no projeto.

Ah, sim! Você quer ver a iluminação no projeto, claro! Então, vamos lá!

Agora que configuramos o Render Pipeline 2D, precisamos alterar as configurações gráficas do projeto para utilizar o nosso novo Pipeline. Para realizar essa alteração, precisamos acessar a opção: Edit -> Project Settings e em seguida selecionar a opção Graphics.

Abrindo as configurações do projeto (Project Settings)
Abrindo as configurações do projeto (Project Settings)

Na opções gráficas do projeto (Graphics), precisamos associar o Render Pipeline Asset que criamos anteriormente, sendo necessário apenas selecioná-lo após clicar na opção Render Pipeline Asset, conforme pode ser visto a seguir:

Alterando as configurações gráficas do Render Pipeline
Alterando as configurações gráficas do Render Pipeline

Ta-da! Pronto! Qual tal agora?

...sério? Mais uma vez, nada mudou. :(

Ok...ok...você quer mudança no visual, já entendi!

Se é mudança visual que você quer, então vamos lá!
Agora que finalmente temos tudo configurado, precisamos fazer uma pequena alteração antes de trabalhar com iluminação 2D. Basta alterar todos os nossos sprites para utilizar o material Sprite-Lit-Default.

Entendi! Legal...espera! Você disse TODOS os sprites? Manualmente?

Ops...não, não. Calma! Precisamos mudar o material de todos os sprites, sim. Mas nesse caso, não precisa ser feito manualmente. A Unity fornece um atalho para isso. Basta selecionar a opção Upgrade Scene 2D Renderer através do menu Editt -> Render Pipeline -> Universal Render Pipeline -> 2D Renderer -> Upgrade Scene 2D Renderer.

Em seguida, a Unity exibirá um aviso sobre a atualização. Para prosseguir com a atualização, selecione a opção Proceed.
Alerta sobre a atualização do renderer 2D
Alerta sobre a atualização do renderer 2D


Ao confirmar, nossa cena ficará completamente escura, como por ser visto abaixo:

Cena totalmente escura
Cena totalmente escura

Você sabe o que essa cena escura significa?
Isso significa que funcionou! Temos um jogo pronto para iluminação 2D, mas que ainda não possui iluminação.

Global Light 2D!

Vamos adicionar a nossa primeira luz 2D ao jogo, clicando com o botão direito na hierarquia do projeto e selecionando a opção Light -> 2D -> Global Light 2D (Experimental).

Adicionando luz Global
Adicionando luz Global

Ao adicionar a luz global 2D (Global Light 2D) nossa cena foi automaticamente iluminada. Porém, ainda precisamos ajustar algumas configurações, para deixar a nossa cena com o visual que desejamos.
Vamos dar uma olhada nas propriedades da Global Light 2D, através do Inspector, antes de iniciarmos as nossas alterações.
Propriedades da luz Global
Propriedades da luz Global

Sorting Layers

A primeira alteração que precisamos fazer é na propriedade Target Sorting Layers. Essa propriedade define quais Sorting Layers serão afetados pela luz 2D. Por padrão, o valor Default é atribuindo, significando que apenas os sprites que estiverem no Sorting Layer chamado Default serão iluminados pela luz.

Eu entendi o conceito...mas o que é um sorting layer?

Caso você não lembre o que é um sorting layer, aqui vai uma breve explicação: o sorting layer serve como uma forma de definir a prioridade de renderização (exibição) de um sprite, ou seja, define qual sprite deve ser exibido na frente (sobre os outros sprites) ou mais atrás (embaixo dos outros sprites). Nós podemos agrupar vários sprites em um único sorting layer, que no caso da luz 2D, será utilizado para determinar quais desses "grupos" de sprites serão iluminados.

Agora que lembramos o que é um sorting layer, vamos alterar a nossa luz para influenciar todos os sortings layers do nosso jogo, simplesmente porque queremos que a luz global tenha influência sobre a iluminação de todo o jogo. Ok?
Para isso, precisamos apenas selecionar a opção All na propriedade Target Sorting Layers.

Definição dos sorting layers iluminados pela luz Global
Definição dos sorting layers iluminados pela luz Global

Obs: caso queira que a iluminação influencie apenas sorting layers específicos, basta selecioná-los individualmente na opção Target Sorting Layers.

Intensidade

Agora que a nossa luz global influencia todos os nossos sprites, vamos falar sobre outra propriedade chamada Intensity (intensidade).
Por padrão, a intensidade (Intensity) da luz possui valor 1, ou seja, os sprites influenciados pela Global Light 2D serão exibidos com o brilho padrão do sprite.


Luz global com intensidade 1
Luz global com intensidade 1

Para que os sprites sejam exibidos com um brilho acima do padrão, a intensidade (Intensity) da luz deverá possuir um valor maior do que 1.

Luz global com intensidade 2
Luz global com intensidade 2

O contrário também é verdadeiro, ou seja, para exibir os sprites com um brilho menor que o padrão do sprite, a intensidade da luz deverá ser defina com um valor menor que 1.

Luz global com intensidade 0.5
Luz global com intensidade 0.5

Para o nosso exemplo, vamos seguir com a intensidade (intensity) com o valor de 0.5, como por ser visto na imagem abaixo:

Propriedades da luz Global com intensidade 0.5
Propriedades da luz Global com intensidade 0.5

Sprite Light 2D

O segundo tipo de luz que vamos adicionar ao nosso é conhecido como Sprite Light 2D que pode ser adicionada ao jogo através do menu Light -> 2D -> Sprite Light 2D (Experimental).

Criando Sprite Light 2D
Criando Sprite Light 2D

Como o próprio nome sugere, a Sprite Light 2D utiliza a forma de qualquer sprite para definir como a luz será projetada nos sprites do jogo.
Ao adicionar a Sprite Light 2D podemos ver que nenhum sprite é definido como padrão, fazendo com que nenhuma luz seja projetada.
Propriedades do Sprite Light 2D
Propriedades do Sprite Light 2D

No nosso projeto, vamos configurar a nossa luz 2D para iluminar sobre uma área circular, com visual pixelado nas bordas, ao redor do nosso personagem, conforme mostramos lá no começo do post.
Para configurar a nossa Sprite Light 2D dessa forma, precisamos selecionar o sprite que será utilizado na projeção da luz. Isso pode ser feito através da pripriedade Sprite da Sprite Light 2D, conforme abaixo:
Definindo o sprite que dará forma a Sprite Light 2D
Definindo o sprite que dará forma a Sprite Light 2D

Embora o sprite utilizado para projetar a luz já tenha sido definido, você deve ter percebido que a nossa Sprite Light 2D ainda não está projetando luz sobre os sprites do jogo. Isso acontece porque nós ainda não definimos quais sorting layers (lembra deles?) serão iluminados pela luz 2D.

Sprite Light 2D ainda não causando efeito na cena
Sprite Light 2D ainda não causando efeito na cena

A seleção dos sorting layers pode ser feita da mesma que fizemos anteriormente, selecionando a opção all, já que o nosso objetivo é permitir que essa luz 2D possa iluminar todos os sprites do nosso jogo.

Definição dos sorting layers iluminados pela Sprite Light
Definição dos sorting layers iluminados pela Sprite Light

Após alterar o Target Sorting Layers todos os sprites do nosso jogo passam a ser iluminados por nossa Sprite Light 2D, dependendo a posição da luz no mapa, como podemos ver abaixo, o efeito da iluminação enquanto movimentamos a luz pela dungeon do jogo.

Movendo a Sprite Light 2D pela cena
Movendo a Sprite Light 2D pela cena

Nesse momento, a nossa Sprite Light 2D está configurada para iluminar todo o jogo, mas além de não estar com o efeito pixelizado que comentamos anteriormente, ela também não está seguindo o jogador, durante o jogo, como mostramos no início do post.
Antes de continuarmos com a adição de outro tipo de luz, vamos concluir essas configurações para o comportamento desejado para a Sprite Light 2D.

Para que a nossa luz possa seguir o jogador, precisamos simplesmente arrastar a luz para dentro do objeto Jogador na hierarquia do projeto, fazendo com que o objeto Sprite Light 2D se torne um objeto filho do Jogador.

Definindo a Sprite Light 2D como um objeto filho do Jogador
Definindo a Sprite Light 2D como um objeto filho do Jogador

Agora, se executarmos o jogo, a luz estará seguindo o jogador...perfeito, certo?

Sprite Light 2D seguindo o jogador na posição errada
Sprite Light 2D seguindo o jogador na posição errada

Bem...mais ou menos certo.
O que aconteceu de errado?!

Não precisa se preocupar, isso é bem simples de resolver. Embora a luz esteja seguindo o jogador, nós esquecemos de definir qual é a posição da luz em relação ao jogador. Essa configuração pode ser feita facilmente através do Inspector da luz 2D, alterando a posição dela para 0, 0 e 0 nos eixos x, y e z.

Posicionando a Sprite Light 2D na posição 0, 0, 0
Posicionando a Sprite Light 2D na posição 0, 0, 0

Após posicionarmos a luz corretamente, precisamos garantir que ela será exibida com o visual pixelado que desejamos.
A forma como um sprite é exibido no jogo está diretamente relacionada com as configurações desse sprite no projeto. No caso dessa suavização visual, onde os pixels que formam a imagem ficam menos aparentes, esse efeito é causado pelo filtro aplicado na imagem. Quando trabalhamos com Pixel Art recomenda-se não utilizar filtros, para que os pixels possam ser renderizados da forma como foram desenhados.
Para alterarmos esse filtro do sprite, precisamos selecionar o nosso sprite que dá forma à nossa luz, na aba projeto, e em seguida seleciona a opção Point (no filter) no Inspector, para que o sprite seja renderizado sem filtro. Esses passos podem ser vistos a seguir:

Removendo o filtro de renderização do sprite utilizado como forma para a Sprite Light 2D
Removendo o filtro de renderização do sprite utilizado como forma para a Sprite Light 2D

E o resultado final das configurações da Sprite Light 2D aplicados no jogo ficou asism:

Jogador movendo pela cena, sendo acompanhado pela luz
Jogador movendo pela cena, sendo acompanhado pela luz

Agora que temos a nossa Sprite Light 2D configurada, podemos seguir para o último tipo de luz que utilizaremos neste exemplo, o Point Light.

Point Light 2D

O Point Light 2D, por mais incrível que pareça, representa um ponto de luz, pois é isso mesmo.
De forma semelhante ao que foi feito anteriormente com a Global Light 2D e com a Sprite Light 2D, para criarmos um Point Light 2D precisamos acessar a opção Point Light 2D (Experimental) através do menu Light -> 2D -> Sprite Light 2D (Experimental).

Adicionando Point Light 2D
Adicionando Point Light 2D

Assim como as demais luzes adicionadas anteriormente, para que o Point Light 2D possa iluminar os sprites do jogo, precisamos definir quais sorting layers serão influenciados pela iluminação.

Definição dos sorting layers iluminados pelo ponto de luz
Definição dos sorting layers iluminados pelo ponto de luz

Mais uma vez, como queremos que o nosso ponto de luz possa iluminar qualquer sprite do jogo, selecionamos a opção All no Target Sorting Layers. A partir dessa configuração, podemos observar que a luz começa a fazer efeito no nosso jogo.

Além de definir o sorting layer, também vamos posicionar a luz sobre o objeto o sprite que representará o ponto de emissão em nosso jogo.

Posicionamento do ponto de luz
Posicionamento do ponto de luz


Em seguida, vamos alterar as propriedades Color, Intesity e Outer Radius para que a iluminação fique compatível com o objeto brilhante que representa o emissor da luz no jogo.

Configuração da cor, intensidade e raio de ação do ponto de luz
Configuração da cor, intensidade e raio de ação do ponto de luz

Color
A propriedade Color representa a cor da luz, ou seja, quando um objeto for iluminado por este Point Light 2D, qual cor será adicionada ao sprite iluminado. Neste exemplo, escolhemos uma cor laranja, por ser facilmente associada ao nosso objeto emissor de luz.

Intensity
Alteramos a intensidade da luz de 1 (valor original) para 1.5, para que os sprites iluminados pelo Point Light 2D tenham o seu brilho aumentado em 50%, quando comparado ao valor original 1.

Outer Radius
Por último, alteramos o tamanho do outer radius, com objetivo de aumentar a área de ação do nosso Point Light 2D, permitindo que ele ilumine uma área ligeiramente maior. Embora a alteração tenha sido realizada diretamente na cena (scene), ela também pode ser feita através do Inspector, para definir valores mais precisos.

Após todas essas configurações o nosso jogo parece estar quase pronto.
Como podemos ver na imagem a seguir, a iluminação ao redor do jogador parece se destacar demais em relação aos demais elementos do jogo.

Jogo com destaque excessivo na iluminação do jogador
Jogo com destaque excessivo na iluminação do jogador

Para evitar essa sensação de estranheza por parte do jogador, decidimos reduzir a intensidade do Sprite Light 2D de 1 para 0.5, resultando na versão final do nosso exemplo:

Versão final da iluminação do jogo
Versão final da iluminação do jogo

O projeto desenvolvido neste post pode ser baixado aqui.

E aí, o que achou?
Deixe o seu comentário com sugestões e feedbacks. Até mais! o/

Comentários

Postagens mais visitadas deste blog

Transição de Fases (navegação entre Cenas) na Unity

GetComponent - Obtendo a referência para outros componentes do GameObject

[POO] Herança na Unity