Menu

17 – Tutorial Intermediário – Medusa

Depois de um post mais pesadinho como foi o passado com portais, foreground de agua, serra e tudo mais, vamos pegar um pouco mais leve hoje, né?

Bom, o nosso inimigo da vez será uma medusa marinha, aqueles bichos parecidos água-viva.

Para o sprite utilizaremos o JellyFish disponibilizado por Nash no site OpenGameArt:

http://opengameart.org/content/cartoon-jelly-fish

Nós basicamente iremos utilizar apenas os sprites idle (para morrendo) e swim (para nadando). Então pode adiciona-los a pastas Resources/sprites/inimigos/medusa:

44- Tutorial Fase 2 - Inimigo

Após isso, basta criar um objeto na Scene com o nome Medusa e depois ir a aba Animation para criar as animações nadando, atacando e morrendo:

45- Tutorial Fase 2 - Inimigo

48- Tutorial Fase 2 - Inimigo

Nas animações morrendo e atacando lembrem-se de remover o Loop Time.

Bom, como já deu para perceber inimigo não irá surgir, então também não precisa da animação escondido. Na animação nadando, basta mover os sprites da pasta nadando e ajustar o sample para um valor que ache legal. Já na animação morrendo, além de arrastar os sprites pode mudar a cor do ultimo keyframe para vermelho se quiser enfatizar, já que não temos uma animação legal:

47- Tutorial Fase 2 - Inimigo

Na animação atacando, jogue novamente os sprites nadando. Só que aqui iremos aplicar uma cor amarela alterando com a cor branca (normal) no sprite. Então clique no segundo keyframe e altera a cor do sprite:

49- Tutorial Fase 2 - Inimigo

Agora é só dá ctrl+c nesse novo keyframe da linha Medusa: Sprite Renderer.Color e sair colocando nos sprites de número par:

50- Tutorial Fase 2 - Inimigo

Depois copie o primeiro keyframe da linha Medusa: Sprite Renderer.Color que possui a cor branca e jogue nos sprites impares:

51- Tutorial Fase 2 - Inimigo

Isso fará nossa meduza piscar quando acertar o personagem.

Em seguida, com a opção de Record da animação desmarcada, adicione o Circle Collider 2D (Pode usar um sprite qualquer para se guiar no formato do inimigo) e o Rigidbody2D com a opção Is Kinematic marcada para não ter efeitos da gravidade no inimigo (Se você não colocar, os ataques não dos personagens não vão funcionar).

52- Tutorial Fase 2 - Inimigo

53- Tutorial Fase 2 - Inimigo

Agora na aba Animator (Com o objeto Medusa na aba Hierarchy selecionado), vamos criar os parâmetros do tipo Trigger morreu e atacou:

54- Tutorial Fase 2 - Inimigo

A primeira animação a ser executada é a nadando. Depois basta fazer as seguintes transições:

nadando -> atacando (Condição: atacou | Has Exit Time: Não | Transition Duration: 0)
atacando -> nadando (Condição:nada | Has Exit Time: Sim | Transition Duration: 0)
Any State -> morrendo (Condição:morreu | Has Exit Time: Não | Transition Duration: 0)

55- Tutorial Fase 2 - Inimigo

Bem simples assim. Agora tecnicamente só precisamos criar o script do inimigo. Neste caso crie um script chamado Medusa dentro da pasta scripts/inimigos/

60- Tutorial Fase 2 - Inimigo

Esse script vai herdar de Inimgo, então a sua estrutura inicial será:

Script: Medusa.cs

using UnityEngine;
using System.Collections;
using System;

public class Medusa : Inimigo {

    protected override void atacar() { }

    protected override void mover() {
        
    }
}

E qual é a primeira coisa que sempre temos que fazer para não esquecer? Definir o status do inimigo:
Script: Medusa.cs

    protected override void Awake() {
        base.Awake(); //Chama o Awake da classe Inimigo
        status = new Status(15, 0, 4); //HP = 15 | MP = 0 | Ataque = 4
    }

Assim como foi no passado, o nosso inimigo não irá ter nada no método atacar. O ataque dele será ao encostar no personagem, então já podemos até adicionar o método OnCollisionStay2D, verificando se tocou no personagem e se tocou causando dano e ativando a animação:

Script: Medusa.cs

    void OnCollisionStay2D(Collision2D colisor) {
        if (colisor.gameObject.tag.Equals("Player") && !status.estaMorto()) {
            var personagem = colisor.gameObject.GetComponent();
            personagem.recebeDano(status.getAtaque());
            animator.SetTrigger("atacou");
        }
    }

Igualzinho ao do Zumbi. Agora em relação ao movimento, nós já fizemos um script movendo de uma posição X para outra no Zumbi. Já fizemos um script movendo na diagonal no Andromalius e também de uma posição qualquer a outra na Serra. Agora iremos fazer o objeto ficar seguindo sempre o personagem, igual a câmera, porém terá uma coisa diferente. Mas por hora, vamos cuidar apenas do movimento seguindo o personagem, então vamos criar uma variável para guarda a velocidade e outra para guardar a posição do jogador:

Script: Medusa.cs

    public float velocidade;    //Velocidade do Inimigo
    private Transform jogador;  //transform que o inimigo vai seguir

No método Start, podemos buscar quem é o jogador!

Script: Medusa.cs

    void Start() {
        jogador = GameObject.FindGameObjectWithTag("Player").transform;
    }

Colocamos no método Start devido ao fato de que estamos buscando conteúdo de outros objetos que podem não estar configurados / ou criados no método Awake.

Para movimentar, podemos simplesmente usar o MoveTowards já que não queremos uma movimentação suave, certo?

Script: Medusa.cs

    protected override void mover() {
        transform.position = Vector3.MoveTowards(transform.position, jogador.position, velocidade * Time.deltaTime);
    }

Bem simples e o script já poderia acabar por aqui, afinal a parte de dano sofrido já está implementada no script Inimigo. Porém queremos que a Medusa esteja virada sempre na direção do personagem, para isso vamos usar um método para rotacionar. Nos jogos 3D, basta a gente usar o método LookAt que o transforma já vira em direção da posição:

transform.LookAt(jogador)

Porém para jogos 2D, não é tão fácil assim não. Não lembro se foi nesse tutorial ou foi em outro que eu falei sobre o rotation e o eulerAngle. O eulerAngle retorna a rotação em graus, e o rotation retorna a rotação em relação ao mundo do jogo. Aqui nós vamos utilizar o método Quaternion.LookRotation que retorna justamente essa rotation.
Para usar o Quaternion.LookRotation, temos que informar a direção da rotação (semelhante aquilo que fizemos lá com o Andromalius, do Vector3 com as posições nas diagonais). Aqui podemos identificar a direção subtraindo a posição do jogador com a posição do inimigo:

var direcao = jogador.transform.position – transform.position;

Depois buscamos a rotação e a aplicamos a rotação no inimigo sem alterar as rotações em X e Y, apenas em Z:

Script: Medusa.cs

    protected override void mover() {
        transform.position = Vector3.MoveTowards(transform.position, jogador.position, velocidade * Time.deltaTime);

        //Rotaciona
        var direcao = jogador.transform.position - transform.position;
        var rotacao = Quaternion.LookRotation(direcao, transform.TransformDirection(Vector3.up));
        transform.rotation = new Quaternion(0, 0, rotacao.z, rotacao.w);
    }

“Carlos, o que é o rotacao.w?”

Fico te devendo essa, nunca entendi exatamente o que é o quarto parâmetro da rotação.

O Quarterion.LookRotation vai informar a rotação correta. E o transform.TransformDirection(Vector3.Up) informa qual é a posição para cima em relação ao objeto.

Com isso, sua Medusa já deve estar girando na mesma direção do personagem:

57- Tutorial Fase 2 - Inimigo

58- Tutorial Fase 2 - Inimigo

Agora um ajuste que podemos fazer na Medusa é fazer com que ela não fique empurrando o personagem ao encostar-se a ele. Para isso, só precisamos criar uma variável privada (bool encostado) para verificar se o personagem está ou não encostado:

Script: Medusa.cs

using UnityEngine;
using System.Collections;
using System;

public class Medusa : Inimigo {

    public float velocidade;        //Velocidade do Inimigo
    private Transform jogador;      //transform que o inimigo vai seguir
    private bool encostado = false; //Está encostado no alvo

Agora no método Update o inimigo só vai se mover caso não esteja encostado:
Script: Medusa.cs

    protected override void mover() {
        if (!encostado)
            transform.position = Vector3.MoveTowards(transform.position, jogador.position, velocidade * Time.deltaTime);

        //Rotaciona
        var direcao = jogador.transform.position - transform.position;
        var rotacao = Quaternion.LookRotation(direcao, transform.TransformDirection(Vector3.up));
        transform.rotation = new Quaternion(0, 0, rotacao.z, rotacao.w);
    }

Por fim, agora é verificar quando esta ou não encostado. Para isso no OnCollisionStay2D podemos dizer que ele está encostado. E no método OnCollisionExit2D (Esse método só é executado quando um objeto deixa de colidir), informamos que ele deixou de encostar:

Script: Medusa.cs

    void OnCollisionStay2D(Collision2D colisor) {
        if (colisor.gameObject.tag.Equals("Player") && !status.estaMorto()) {
            encostado = true;
            var personagem = colisor.gameObject.GetComponent();
            personagem.recebeDano(status.getAtaque());
            animator.SetTrigger("atacou");
        }
    }

    void OnCollisionExit2D(Collision2D colisor) {
        if (colisor.gameObject.tag.Equals("Player"))
            encostado = false;
    }

Pronto, agora é só voltar no Editor do Unity, adicionar o Script Medusa ao objeto Medusa, informar para pegar seu Animator, informar que ele já está visível e dizer a sua velocidade:

59- Tutorial Fase 2 - Inimigo

Depois disso pode transformar esse inimigo em um prefab para poder usa-lo em outros cantos:

60- Tutorial Fase 2 - Inimigo

“E acabou?”

Nããããããoooo o/, Culpa de quem? Minha u.u

Quando fui testar, senti a falta de algo e lembrei que quando a gente acerta o inimigo, ele muda para a cor vermelha, só que nós já mudamos a cor no Animation, fazendo com que a cor vermelha que definimos ao receber dano seja atualizada para a cor da animação automaticamente. Só não haveria problema se não mudássemos a cor na animação. Então como alternativa, ao invés de alterar para a cor vermelha, vamos alterar o Material, que são ajustes bem simples.

Primeiro é só criar dois materiais com o nome SpriteVermelho e SpriteBranco. O Shader de ambos serão Sprite/Default:

61- Tutorial Fase 2 - Inimigo

Porém a cor usada no SpriteVermelho será vermelha:

62- Tutorial Fase 2 - Inimigo

Agora sim, podemos voltar lá ao nosso script “Inimigo” e trocar no método recebeDano a linha:

GetComponent().color = Color.red;

Por:

GetComponent().material = Resources.Load(“materials/SpriteVermelho”) as Material;

Ao invés de trocar a cor, trocamos o material para o SpriteVermelho que acabamos de criar.

Script: Inimigo.cs

    public void recebeDano(int dano) {
       if (visivel) { 
            status.sofrerDano(dano);

            if (status.estaMorto()) {
                animator.SetTrigger("morreu");                                          //Chama a animação de morte
                var duracaoAnimacao = animator.GetCurrentAnimatorStateInfo(0).length;   //Duração da animação
                Destroy(this.gameObject, duracaoAnimacao);                              //Destroi objeto após animação
                enabled = false;                                                        //Desabilita esse script com os ataques e movimentos
            } else {
                GetComponent().material = Resources.Load("materials/SpriteVermelho") as Material;
                Invoke("corNormal", 0.3f);                            //Normaliza a cor após 0.3 segundo
            }
       }

E depois no método cor normal, basta aplicar o outro material que criamos, SpriteBranco:

Script: Inimigo.cs

    void corNormal() {
        GetComponent().material = Resources.Load("materials/SpriteBranco") as Material;
    }

Pronto, com isso já resolve o problema, já que na animação não trocamos os materials! Foi simples o ajuste, está vendo, não é melhor deixar algo arrumado e bonitinho?

E com isso completamos mais um tutorial! O próximo será um boss que não se move e só ataca, para quem estava achando ruim nenhum inimigo atacar, apenas se mover u.u.

Criador do Jogos Indie, amante de jogos, terror, música, anime e programação. Estudante de mestrado com foco em jogos na educação. Louco por Resident Evil e... sei lá, acho que é isso O.o

7 comments

  1. Wanderson disse:

    Muito bom Carlos obrigado por estar fazendo este tutorial,serio obrigado mesmo sou muito grato
    tenho uma pergunta:Eu gostaria de seguir carreira na área de desenvolvimento de jogo,tenho 14 anos, quais cursos e faculdades devo fazer? em que áreas eu devo ou posso seguir? eu gostaria de ser um programador mas não entendo direito que cursos tenho que fazer e se é possível ganhar a vida com jogo

    • Então Wnaderson para trabalhar com jogos existem diversas areas, como roteirista, produtor, diretor, programador, designer e por ai vai. Se você já sabe o que quer e se de fato é programação, você pode escolher ir para um curso focado em jogos, o que alguns estados já tem.

      Caso o seu estado não tenha (Como o meu) e você quer mesmo ir para programação, vá para ciência da computação ou análise de sistemas, que você irá aprender muita coisa de programação, mas não fique apenas no que ver na faculdade, pois sempre é muito pouco.

      Quanto a ganhar a vida com isso, sim é possível sim, já existe vários brasileiros (Embora ainda menoria), que consegue viver exclusivamente de jogos. Minha recomendação é, primeiro buscar um emprego que te sustente e paralelo você vai desenvolver sua empresa em jogos. Depois que ela tiver firme e ganhando bem, ai sim você se foca nos seus jogos 😉

      E procure sempre outras pessoas interessadas, para formar equipes. Se você é bom em programação, vai precisar de alguém que seja bom em criar roteiros, gerenciar equipes, fazer modelos 3D ou sprites, saber se comunicar com a mídia e por ai vai 😉

  2. Wanderson disse:

    Obrigado, sério obrigado, vou fazer o que voce falou, obrigado pela ajuda

  3. Fabio Pimenta disse:

    Carlos, boa noite. Não consigo baixar o arquivo do Projeto, retorna o erro 404 de arquivo não encontrado.

    “O arquivo que você está procurando foi excluído ou movido de lugar”

    https://www.dropbox.com/s/89t2inhj84eegqv/Tutorial_aula_17.rar?dl=0

Deixe uma resposta

Parceiros

Steam Brasil LoboLimão Centro RPG Lab Indie
Mundo Gamer PodTerror

Anunciantes

Aglomerando - Agregador de conteúdo
Uêba - Os Melhores Links GeraLinks - Agregador de links Piadas Idiotas - São idiotas mas o faz rir Tedioso: Os melhores links LinkLog MeusLinks.com - Informação e conteúdo todos os dias para você! Agregador de Links - Madruga Links 4Blogs - Agregador de conteúdo Está no seu momento de descanso né? Entao clique aqui!