[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

Update, LateUpdate e FixedUpdate

Update é o método mais comumente usado para executar ações que precisam ser realizadas com frequência e/ou repetidas vezes em diferentes frames do jogo, mas você sabia que existem outros métodos similares ao Update e que podem ser usados para propósitos mais específicos? Esses outros métodos são o LateUpdate e o FixedUpdate.

Update

Adicionado automaticamente pela Unity sempre que um novo script é criado, o Update é executado a cada frame do nosso jogo, ou seja, se o jogo está sendo executado a 60 FPS (frames por segundo), isso significa que o método Update de cada um dos nossos scripts será executado 60 vezes por segundo.
Por ser um método executado com tanta frequência, é fácil ficar tentado a colocar toda a lógica de atualização do seu jogo no Update, mas é preciso ter cuidado. Quanto mais pesado (mais lógicas complexas) for o processamento realizado no método Update, menor será o FPS (taxa de atualização em frames por segundo) do seu jogo.

O recomendado é que apenas lógicas que precisam ser executadas todos os frames estejam presentes no Update, como por exemplo, a detecção de inputs do jogador. No exemplo abaixo nós podemos ver como identificar se uma tecla específica foi pressionada:

using UnityEngine;

public class Controles : MonoBehaviour {

    public Personagem personagem;

    public void Update() {
        if (Input.GetKeyDown(KeyCode.W)) {
            // W foi pressionado. 
            // Move o personagem para cima
            personagem.MoverCima();
        } else if (Input.GetKeyDown(KeyCode.S)) {
            // S foi pressionado.
            // Move o personagem para baixo
            personagem.MoverBaixo();
        } else if (Input.GetKeyDown(KeyCode.A)) {
            // A foi pressionado.
            // Move o personagem para esquerda
            personagem.MoverEsquerda();
        } else if (Input.GetKeyDown(KeyCode.D)) {
            // D foi pressionado.
            // Move o personagem para direita
            personagem.MoverDireita();
        }
    }

}

LateUpdate

O LateUpdate também é um método executado a cada frame do seu jogo. O termo "late" pode ser traduzido do inglês como tarde, tardio ou até mesmo atrasado. Sabendo disso, fica fácil entender qual é a principal diferença do Update para o LateUpdate.

O LateUpdate é uma opção de método para realizar atualizações a cada frame, mas tendo a certeza de que ele sempre será executado com um "atraso" em relação ao Update, ou seja, a cada frame do nosso jogo, primeiro o Update de todos os scripts são executados e só depois da conclusão de todos os Updates é que a execução do LateUpdate de cada um dos script é iniciada.

Esse comportamento de execução com atraso é bem interessante e pode nos ajudar bastante na construção de mecânicas que só podem ser executadas após o ciclo de Update ser concluído.
Um exemplo de mecânica comumente associada com LateUpdate é a movimentação da câmera do jogo seguindo o jogador. Como a Unity não garante a ordem de execução do Update entre diferentes scripts, coordenar a atualização da posição do personagem e a atualização da posição da câmera de forma que a posição do jogador sempre fosse realizada primeiro, seria um trabalho muito mais difícil sem a ajuda do LateUpdate.
Com o LateUpdate, basta realizar a lógica de movimentação do jogador no Update e implementar lógica de movimentação da câmera, para seguir o jogador, no LateUpdate. Dessa forma, quando a lógica de movimentação da câmera for executada, você terá certeza de que a posição do jogador já foi atualizada, já que o Update sempre é executado antes de qualquer LateUpdate

using UnityEngine;

public class MeuJogo : MonoBehaviour {

    public Personagem personagem;
    public ControladorCamera controladorCamera;

    public void Update() {
        // Executa a movimentação do personagem
        this.personagem.Mover();
    }

    public void LateUpdate() {
        // Move a câmera para seguir o personagem,
        // sempre após o Update ter sido executado,
        // garantindo que a movimentação do personagem
        // já foi concluída.
        this.controladorCamera.SeguirJogador();
    }

}

FixedUpdate

Seguindo o mesmo princípio da explicação do LateUpdate, vamos primeiro entender o nome FixedUpdate. Fixed pode ser traduzido do inglês como fixo ou constante, no caso do FixedUpdate o termo "fixo" está relacionado ao intervalo de tempo entre a execução deste método.
Enquanto o Update e o LateUpdate sempre são executados a cada frame, o FixedUpdate é executado a cada 0,02 segundos (50 vezes por segundo), ou algo bem próximo disso.

Esse valor de 0,02 é o padrão definido pela Unity, mas ele pode ser alterado nas configurações do projeto. Embora a Unity não garanta que o FixedUpdate vai ser executado exatamente a cada 0,02 segundos, a Unity fará o possível para que este método seja executado em intervalos de tempo próximos deste valor, garantindo uma execução constante do FixedUpdate durante o decorrer do jogo.

Por ser um método executado em intervalos fixos, não existe a garantia de que ele será executado em todos os frames do jogo, nem quantas vezes será executado por frame. Quanto maior a taxa de FPS (frames por segundo) do jogo, mais Updates serão executados entre um FixedUpdate e outro. Da mesma forma, quanto menor a taxa de frames por segundo, menos Updates serão executados entre um FixedUpdate e outro. 

A figura abaixo ilustra 30 frames da execução de um jogo, onde cada linha representa um método de atualização (Update, LateUpdate e FixedUpdate) que foi executado naquele frame específico (de 1 até 30). Nesta mesma figura, as células vazias/brancas simbolizam que aquele método não foi executado no frame específico.

Execução dos métodos de atualização em uma sequência de 30 frames

O FixedUpdate está fortemente relacionado com o sistema de física da Unity, por isso, ele é recomendado para ser utilizado com operações da física como, por exemplo, interagir com um Rigidbody de um GameObject, da mesma forma como pode ser visto no trecho de código abaixo:

using UnityEngine;

public class Jogador : MonoBehaviour {

    public Rigidbody rigidbody;
    
    // Impulso aplicado para o jogador pular
    private int impulsoPulo = 20f;

    // Identificar se uma força deve ser aplicada
    // para fazer o jogador pular
    private bool pular;
    

    public void Update() {
        // Tecla ESPAÇO foi pressionada
        if (Input.GetKeyDown(Input.Space)) {
            // Marca o jogador como pronto para pular
            this.pular = true;
        }
    }

    public void FixedUpdate() {
        // Caso o jogador esteja pronto para pular
        if (this.pular) {
            // Aplica uma força no Rigidbody do jogador
            // para executar a ação de pulo
            Vector3 forcaPulo = (this.transform.up * this.impulsoPulo);
            this.rigidbody.AddForce(forcaPulo, ForceMode.Impulse);

            // Reinicia a variável do pulo, para não aplicar
            // a força mais de uma vez
            this.pular = false;
        }
    }

}


E aí, você conhecia esses três métodos de atualização (Update, LateUpdate e FixedUpdate) e as suas diferenças? Comenta aí!


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