[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

Introdução GameObjects e Components

 Hey, você! Estamos de volta, mais uma vez, mas dessa vez para falar sobre GameObjects, Components, MonoBehaviours e o ciclo de vida dos scripts. Pronto para continuar?

GameObjects
Cada objeto (personagem, inimigos, itens, cenário e etc.) do jogo é um GameObject. Imagine um GameObject como um container (um agrupador). Esse agrupado serve para representar o objeto do seu jogo como uma coisa só, ou seja, um objeto que representa o todo. Essa representação é feita através da composição de componentes, para fazer o objeto (GameObject) funcionar e se comportar como o esperado. Um pouco confuso? Não se preocupe, é mais simples do que parece.

Por si só, um GameObject não é muita coisa e sozinho não pode fazer nada no jogo. Sendo ainda mais claro, você não pode (nem consegue) criar um GameObject sem nenhum componente nele. Para criar um GameObject "vazio" (empty) na Unity, basta clicar com o botão direito do mouse na Hierarquia (Hierarchy) e selecionar a opção Create Empty.

Criando um objeto vazio

An wild Pokémon Um GameObject apareceu na Hierarquia, com o nome padrão "GameObject"

Novo GameObject na Hierarquia

Quando selecionado, o Inspector mostrar as propriedades do GameObject "vazio" como pode ser visto na imagem abaixo:

Propriedades do GameObject "vazio"

Como você pode ver, quando um GameObject é criado, o componente Transform é automaticamente adicionado nele. Mas espera um pouco...o que é um Transform?


Components
Quando falamos sobre componentes (Components), pense neles como um script (um arquivo de código de programação) que é responsável por um comportamento específico. A Unity fornece uma variedade de componentes prontos para agilizar o processo de desenvolvimento de jogos, mas nós podemos criar nossos próprios componentes, implementando Scripts com a linguagem de programação C# (C Sharp).

Representação do GameObject como um container (agrupador) de componentes

Transform
O primeiro componente sobre o qual nós vamos falar é o Transform. O Transform é automaticamente adicionado ao GameObject quando ele é criado, e nós não podemos adicioná-lo ou removê-lo em momento algum.
Transform é responsável pela representação espacial do GameObject dentro do mundo 2D/3D da Unity. Mas o que eu quero dizer com "espacial"?
Bem...o Transform define a posição (onde o GameObject está), a rotação (para onde o GameObject está "olhando") e a escala (tamanho normal, expandido ou encolhido).

Transform com valores padrão

O valor padrão da posição e da rotação é (0, 0, 0), o que significa que o GameObject está posicionado no centro do mundo e está olhando para a frente (comparado com o eixo/direção global do mundo), e a escala padrão é (1, 1, 1) para representar um objeto em seu tamanho normal (nem expandido, nem encolhido).

Ok, eu entendi o que o Transform é, mas como eu uso ele?
Bem, sabendo que a posição define onde o objeto está posicionado, se você quiser mover o objeto dentro no mundo 2D/3D, você precisa apenas mudar o valor do atributo "position" (posição) do Transform, por exemplo.
Position (posição), Rotation (rotação) e Scale (escala) são representados por um Vector3, que por sua vez é um tipo de dados formado por três números reais: x, y e z.
Os valores de x, y e z representam a posição, rotação ou escala do objeto em cada um dos eixos de um mundo tridimensional. Nós podemos mudar o valor do eixo x para mover o GameObject da esquerda para a direita. Ao alterar o eixo y, nós podemos mover o objeto de cima para baixo, e se nós mudarmos o eixo z, nós poderemos mover o GameObject de frente para trás. Fácil, certo?!

Adicionando mais componentes
GameObjects são como containers (agrupadores) de componentes, certo? Como nós podemos adicionar outros componentes, e por que nós deveríamos fazer isso?

Bem, lembre que componentes são responsáveis por um comportamento específico. Existem vários componentes disponíveis na Unity para nos ajudar a trabalhar com coisas como renderização (exibir uma imagem na tela, por exemplo), áudio, física, colisões, interface e muito mais. E nós devemos adicionar esses componentes (ou escrever nossos próprios componentes) dependendo do comportamento que a gente queira atribuir ao GameObject.

No fim das contas, o que é um componente?
Um componente não é nada mais que um Script (geralmente um script escrito na linguagem C#), cujo ciclo de execução é controlado pela Unity através de uma pipeline de execução bem definida.

Para criar um Script C# basta clicar com o botão direita dentro da pasta Assets (na aba Project), e selecionar a opção: Create -> C# Script.
Cada novo C# Script será criado pela Unity com o nome NewMonoBehaviour, e nós temos que mudá-lo para um nome mais apropriado, dependendo do que estamos construindo. Neste caso, eu chamei o meu script de MeuScript. Para este exemplo, parece intuitivo o suficiente, não acha?


Se você quer saber com o que se parece um Script C# na Unity, veja a imagem abaixo:

Exemplo de Script C# da Unity

Como você pode ver, nosso script é basicamente uma Classe C#. Mas, existem algumas peculiaridades. Quando você cria um novo Script C# na Unity, o script contém dois métodos por padrão:
  1. Start
  2. Update
É...eu consigo ver isso na imagem anterior, mas por que isso é necessário?

Lembra da pipeline de execução da Unity que mencionamos antes? Bom, está na hora de falarmos um pouco mais sobre ela.
Cada Script C# da Unity herda de um MonoBehaviour, porque o MonoBehaviour é considerado como a classe base de todos os componentes customizados, ou seja, todos os scripts que nós criaremos. Desde que um script herde de um MonoBehaviour, ele estará disponível para ser usado como um componente na Unity.

Ok...mas eu ainda não sei por que os métodos Start e Update são necessários.
Bom...eles não são realmente obrigatórios. Você só precisa manter eles nos seus scripts, se você realmente precisar deles.
Como qualquer outro componente, nossos scripts tem o seu ciclo de vida e a ordem de execução controlada pela Unity. Quando o seu jogo começa a ser executado (o botão "play" é pressionado dentro do editor da Unity, por exemplo), a Unity executará automaticamente os métodos Start de todos os componentes presentes na cena (Scene), se existir algum.
Após executar o método Start de todos os componentes (incluindo os nossos Scripts), a Unity iniciará o ciclo de execução do método Update (também de todos os componentes, um de cada vez), onde o método Update de cada script será executado uma vez por frame, até o fim jogo.

Executado uma vez por frame...você sabe o que isso significa?
Isso significa que, se o seu jogo for executado a 60fps (60 frames por segundo), o método Update de cada um dos componentes será executado 60 vezes a cada segundo.

Start

Para ver como o método Start funciona, vamos adicionar (mais uma vez) uma mensagem de depuração (Debug) que será exibida no Console da Unity quando o método Start for executado. Para adicionar uma mensagem de depuração, utilize o método Debug.Log da classe Debug, com uma mensagem informativa como parâmetro desse método.

Método Start com uma mensagem de depuração para teste

Nós simplesmente temos que pressionar o botão "play" e a mensagem de depuração vai aparecer no Console...certo?
Ops...Nada aconteceu. O que eu fiz de errado?

Se você fez exatamente o que eu fiz, você provavelmente não fez nada errado até agora. Vamos recapitular para verificar se nós realmente fizemos tudo certinho, mas talvez tenhamos esquecido de algo...
  1. Criar um script C#; ✔
  2. O script deve herdar da classe MonoBehaviour, para se comportar como um Componente; ✔
  3. Implementar o método Start para exibir a mensagem de depuração; ✔
  4. Adicionar o script na pipeline de execution da Unity.
Espera um pouco! Você disse que a Unity automaticamente gerencia todos os componentes, e como o a classe MeuScript herda de MnonoBehaviour, ele já é um componente. Sendo assim, o passo 4 já foi feito. Certo?!

...o passo 4 está quase pronto. Nós já temos o script. Agora precisamos apenas adicionar esse script na pipeline de executação da Unity. Se você não faz ideia de como fazer isso, não tem problema. Fazer isso é tão simples quando arrastar o script e soltá-lo sobre qualquer GameObject na Hierarquia. Dessa vez, nós vamos arrastar e soltar o nosso script (MeuScript) sobre o nosso novo GameObject, que ainda está nomeado como "GameObject".


Caso você ainda não tenha um novo GameObject na Hierarquia, você pode revisar como criá-lo no começo desse posto, clicando aqui para voltar lá.

Existe outra forma de adicionar um Componente (incluido Scripts) em um GameObject?

Hmm...sim! Ao selecionar o GameObject na Hierarquia, as propriedades do GameObject serão exibidas no Inspector. Além das propriedades do GameObject, um botão Add Component (Adicionar Componente)  também estará disponível. Se preferir, você pode adicionar qualquer componente em seus GameObjects através desse botão.


Agora que nosso script foi adicionado ao GameObject, podemos apertar o botão play (na parte superior da Unity) para vermos o que acontece.

Pressionar o botão play para executar o jogo no Unity Editor


Logo após pressionar o play, o nosso exemplo começará a ser executado. Com isso, o método do Start do MeuScript também será executado, logo após o início do "jogo", fazendo com que nossa mensagem de teste seja exibida no Console.

"Jogo" em execução

Conforme o esperado, a mensagem "Iniciando o MeuScript" que adicionamos no Start do MenuScript foi exibida no Console, logo após o início da execução.

Mensagem de depuração do MeuScript sendo exibida no Console

É importante destacar que o método Start é executado somente uma vez, e isso acontece logo após o objeto (GameObject) se tornar ativo pela primeira vez no jogo.

Legal, legal...mas e o Update? O que ele faz?

Update

O Update é um método comumente utilizado para realizar atualizações (updates) no estado atual de um objeto, ou seja, alterações nas propriedades do script e/ou do GameObject ao qual o script está associado.
Por se tratar de um método que sempre será executado a cada novo frame do jogo, muitas vezes a lógica principal de um script acaba sendo implementada no Update, com o objetivo de manter o GameObject atualizado em relação a todas as outras alterações ocorridas no jogo, que de alguma forma podem influenciar o seu comportamento.

Relembrando: assim como foi dito anteriormente, o método Update é executado uma vez por frame, ou seja, x vezes por segundo, dependendo de quantos fps (frames por segundo) o nosso jogo estará sendo executado.
Exemplo: se o jogo for executado a 60 frames por segundo, o Update será executado 60 vezes a cada segundo.

Vamos adicionar uma mensagem de depuração também no nosso método Update, para acompanharmos a sua execução a partir do Console da Unity.

Mensagem de depuração no método Update do MeuScript

Após adicionar a mensagem de depuração e salvar as alterações no MeuScript, podemos voltar para a Unity e executar (pressionar o botão play) o nosso exemplo mais uma vez.

Execução do exemplo de código no método Update do MeuScript

Ao executar o nosso exemplo, é possível perceber no Console que a mensagem "Iniciando o MeuScript" é exibida apenas uma vez (por estar localizada no método Start), enquanto a nossa nova mensagem de depuração ("Executando o Update do MeuScript.") adicionada no método Update é executada diversas vezes em um curto espaço de tempo, como pode ser notado pelo contador de mensagens, exibido do lado direito da mensagem de depuração do Update, como mostra a imagem abaixo:

Mensagem de depuração sendo exibida diversas vezes no Console

Muito mais coisa pode ser dita sobre a execução dos métodos Start e Update e como podemos utilizá-los em nossos jogos. Mas, acredito que já falamos demais em um único post e o nosso objeto é simplificar. Que tal seguirmos com esse assunto na prática, utilizando o Start e o Update é um jogo de verdade?

Nos vemos no próximo post.

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