GameDev

Aprendendo a programar jogos em Unity: iniciando a codificação para trocar de personagem

Permitiremos ao jogador escolher uma segunda alternativa de veículo para encarar os desafios de Motorista da Pesada.

em 23/03/2024
Seja bem-vindo(a) ao GameDev: Aprendendo a programar jogos em Unity de hoje! Dando sequência ao processo de desenvolvimento de nosso primeiro platformer, vamos começar a codificar em nosso projeto a funcionalidade de escolha do personagem a ser guiado pelos caminhos das fases do game, além de realizarmos mais alguns ajustes de cunho geral.


Caso esteja lendo pela primeira vez nossa série, sinta-se convidado a juntar-se a nós nesta divertida trilha de aprendizagem. Desenvolvendo projetos práticos de codificação de jogos, iremos conhecer mais sobre a ferramenta Unity, suas características e como utilizá-la para tirar do papel os games que sempre sonhamos em desenvolver.

A partir do primeiro tópico, você poderá aprender os mais diferentes aspectos da programação de games. Abordamos desde a instalação e configuração da ferramenta em seu computador até os tópicos envolvendo a criação das fases de um game, a composição do layout dos itens em cena, a programação dos scripts que controlam os comportamentos e regras que queremos implementar, dentre outros pontos muito interessantes.

No momento, estamos desenvolvendo o platformer 2D Motorista da Pesada. Nesse game, o desafio é coletar todas as caixas de presente espalhadas pelas fases o mais rápido possível. Para isso, o jogador irá guiar um simpático carrinho, que percorrerá continuamente os diferentes caminhos das três fases criadas para essa aventura, tomando muito cuidado com os perigos, tais como as bombas e os abismos, que podem abreviar sua jornada.

No tópico anterior de nossa série, concluímos a elaboração do terceiro estágio do game, realizando a distribuição dos presentes e bombas pelos caminhos, agora bem mais perigosos, devido ao fatal buraco sem fundo que posicionamos estrategicamente entre os objetos que representam o chão da cidade.

Vamos prosseguir em nossa missão, agora disponibilizando para o jogador uma nova escolha de veículo para encarar esses perigos. Venha conosco e vamos juntos nesta jornada rumo a novos conhecimentos!

Ajustes bem-vindos

Um dos ajustes mais interessantes que realizamos nos últimos tópicos foi em relação à movimentação das imagens de fundo das fases, corrigindo um pequeno “desencontro” no deslocamento das partes que as compõem que poderia acabar resultando na exibição de “vãos” entre os sprites, o que não seria nada agradável sob o ponto de vista estético dos estágios que criamos.

Já que, com a referida correção, conseguimos sanar definitivamente esse problema, vamos realizar um pequeno ajuste na primeira fase do game, para que os dois sprites que compõem seu fundo fiquem perfeitamente alinhados, aproveitando a movimentação corrigida.

Para isso, vamos abrir o Unity Hub e clicar duas vezes sobre o item referente ao projeto Motorista da Pesada. Na aba Project, abra a pasta Assets e, por fim, Scenes. Clique duas vezes sobre o ícone da cena Fase01 para realizarmos a edição.

Na aba Hierarchy, selecione o GameObject Parte2, subordinado a Fundo (que, por sua vez, é subordinado a Cenario). Vamos modificar o valor do parâmetro Position X de seu componente Transform para 62.7, conforme ilustrado na imagem a seguir. Certifique-se também de que o valor do parâmetro Position X do componente Transform de Parte1 é zero; caso contrário, altere-o para este valor.

Agora, novamente na aba Hierarchy, iremos selecionar os dois objetos simultaneamente (Parte1 e Parte2). Para ambos, alteraremos os valores dos parâmetros Limite Min e Limite Max de seus componentes Mov Fundo para -62.7 e 62.7, respectivamente. Faça como o indicado na ilustração a seguir:

Dessa forma, aproveitamos também na primeira fase do jogo as melhorias que implementamos para as demais, permitindo que haja o deslocamento contínuo do fundo das cenas sem precisar que uma pequena parte de cada sprite fique sobreposta ao próximo.

Elementos suspeitos

Como pudemos notar ao final do texto anterior, alguns itens bem “suspeitos” estão aguardando para serem utilizados, como uma seta e um veículo diferente, armazenados na pasta Imagens:

Nós iremos aplicar esse conjunto de imagens restantes para possibilitar ao usuário escolher outro veículo para guiar pelas fases do game. No caso, será uma simpática van (perua), forte e valente, pronta para os desafios de Motorista da Pesada.


Para conceder essa opção de escolha ao gamer, vamos utilizar um espaço reservado do menu inicial de nossa aventura. Ainda com a cena Fase01 aberta, clique no menu File e, em seguida, Save, para guardar os ajustes que acabamos de realizar em relação ao fundo do estágio.

Feito isso, na aba Project, abra a pasta Assets e, em seguida, Scenes. Clique duas vezes sobre o ícone que representa a cena MenuInicial, conforme ilustrado a seguir:

Com a cena aberta, na aba Hierarchy, selecione o GameObject Opcao2, subordinado a TelaInicial (que, por sua vez, está subordinado a CanvasMenuInicial). Clique com o botão direito sobre o item e selecione a opção Duplicate. Renomeie a cópia do objeto para “Opcao3”, sem as aspas.

Observe na imagem anterior que, devido a termos configurado anteriormente um componente Vertical Layout Group ao objeto TelaInicial, o novo GameObject já se ajustou na tela, posicionando-se na sequência ao elemento Opcao2.

Vamos selecionar o elemento do meio da lista (objeto Opcao2). Na aba Hierarchy, selecione seu GameObject subordinado (de nome “Text”) e, na aba Inspector, altere o parâmetro Text de seu componente Text para “Escolher personagem”, conforme exemplo a seguir:

Na aba Hierarchy, vamos selecionar o objeto Logo, subordinado a CanvasMenuInicial, e duplicá-lo, assim como fizemos agora há pouco com um dos botões da lista.


Conceda ao novo GameObject o nome de “PersonagemDesenho” e, ainda na aba Hierarchy, volte a selecioná-lo. Na aba Inspector, ajuste o valor do parâmetro Pos Y de seu elemento Rect Transform para 200, conforme indicado na ilustração a seguir:

Essa imagem que posicionamos do lado esquerdo da tela irá representar qual personagem será utilizado na próxima partida a ser iniciada. Definiremos o carrinho original como o personagem “padrão”; portanto, com o GameObject em questão selecionado, na aba Inspector altere o parâmetro Source Image de seu componente Image para o sprite com o nome “carrinho”.

Já tendo a representação visual de qual personagem irá participar da partida na tela, agora é a hora de codificarmos, por meio de um script, como será realizada a troca do carrinho a ser utilizado em nossas aventuras.

Codificando a troca

Na aba Project, abra a pasta Assets e, em seguida, Scripts. Clique duas vezes sobre o ícone do script Partida.

O script Partida, pela sua natureza estática, está nos servindo até o momento para informar aos demais scripts do jogo informações relevantes sobre o tempo restante, quantidade de pontos coletados, dentre outros; independentemente de qual cena esteja carregada no momento.

Iremos acrescentar, então, uma informação extra ao conjunto de dados relevantes para uma partida: qual é o personagem em ação naquele momento. Logo após a linha de código em que há a declaração da variável atualControladorFase, insira o seguinte trecho de código:

        public static char atualPersonagem = 'A';

A variável estática atualPersonagem será a responsável por armazenar a informação de qual personagem está sendo utilizado no momento. Essa informação será representada por um caractere, sendo ‘A’ representante do personagem “original” e ‘B’ do personagem “secundário”.

Salve o script e minimize o Visual Studio, para retornarmos ao editor do Unity. Na aba Project, ainda com a pasta Scripts aberta, clique com o botão direito sobre uma área vazia da pasta, selecione a opção Create e, em seguida, C# Script. Dê o nome de “SelecionarPersonagem” ao novo script e clique duas vezes sobre seu ícone para iniciarmos sua edição no Visual Studio.

Primeiramente, iremos declarar duas variáveis públicas, que irão armazenar os sprites dos dois personagem que estarão à disposição dos jogadores para iniciar as aventuras:

Antes da declaração inicial da função void Start(), insira a seguinte linha de código:

        public Sprite personagemA, personagemB;

Dentro dos colchetes da função função void Start(), insira o seguinte trecho de código, que será responsável por verificar qual personagem estará em ação no referido momento e alterar o parâmetro sprite de um componente Image ou SpriteRenderer para o desenho do veículo escolhido:

        if (gameObject.name.StartsWith("Personagem"))
        {
            if (gameObject.GetComponent<Image>() != null)
            {
                if (Partida.atualPersonagem == 'A')
                    gameObject.GetComponent<Image>().sprite = personagemA;
                else gameObject.GetComponent<Image>().sprite = personagemB;
            }
            else if (gameObject.GetComponent<SpriteRenderer>() != null)
            {
                if (Partida.atualPersonagem == 'A')
                    gameObject.GetComponent<SpriteRenderer>().sprite = personagemA;
                else gameObject.GetComponent<SpriteRenderer>().sprite = personagemB;
            }
        }

Por fim, logo após o fechamento dos colchetes da função void Start() — e antes do último fechamento de colchete do arquivo —, iremos introduzir uma função pública de nome TrocarPersonagem, responsável por efetivamente realizar a troca do parâmetro atualPersonagem e acionar novamente a sequência de ações programadas para a função Start():

    public void TrocarPersonagem()
    {
        if (Partida.atualPersonagem == 'A')
            Partida.atualPersonagem = 'B';
        else Partida.atualPersonagem = 'A';

        Start();
    }

Salve o script, minimize o Visual Studio e volte ao editor do Unity para continuarmos o processo de implementação dessa funcionalidade.

Apontando possibilidades

Na aba Hierarchy, vamos clicar com o botão direito do mouse sobre o objeto CanvasMenuInicial, selecionar a opção UI e, em seguida, Image, para criarmos mais um objeto gráfico subordinado ao GameObject selecionado.


Dê o nome de “Seta” para o novo GameObject criado. Em sua aba Inspector, altere o valor do parâmetro Source Image de seu componente Image para o arquivo de imagem de nome “seta”, conforme ilustração a seguir:

E o que essa seta estaria fazendo em nosso menu? Ela vai ser responsável por indicar ao jogador qual é o personagem em questão que será utilizado na partida. Para isso, altere os valores dos parâmetros de seu componente Rect Transform como se segue:
  • Âncoras: Middle Left;
  • Pos X = 300;
  • Pos Y = -100;
  • Width = 50;
  • Height = 200; e
  • Rotation Z = 90.
Veja que a seta está posicionada sobre o botão de escolha do personagem, apontando diretamente para a ilustração que inserimos há pouco. Porém, para que a seta não “atrapalhe” possíveis cliques sobre Opcao2 realizados em suas proximidades, vamos realizar uma alteração em um parâmetro de seu componente Image.

Talvez você se lembre de quando utilizamos raycasts para identificar se haveria chão (ou uma plataforma) abaixo de nosso personagem principal. O conceito de recorrer a um “raio invisível” para se detectar algo é utilizado pelo Unity, também, para informar aos objetos de interface de usuário se houve um clique sobre seus elementos.

Na prática, é como se, ao clicar em um botão na tela, a seta de seu mouse (ou a ponta de seu dedo, em uma tela de toque) disparasse um raycast em direção ao objeto que, ao ser colidido, realiza uma determinada ação programada.

Para impedir que a seta que inserimos na tela seja alvo desse raycast indesejado, em seu componente Image deixaremos a caixa de seleção do parâmetro Raycast Target vazia:


Dessa forma, ao se clicar sobre a seta, ela deixará o raycast “passar” por si, colidindo com o próximo objeto: no caso, o botão posicionado atrás da seta.

Botões e elementos gráficos

Por ter sido gerado através de duplicação, Opcao3 apresenta, até o momento, o mesmo comportamento que Opcao2 ao ser clicado: oculta-se TelaInicial e exibe-se TelaSobre. Porém, com as modificações que realizamos até o momento, será interessante realizarmos alterações em alguns aspectos do comportamento dos dois objetos, retratando as novas funcionalidades implementadas e levando em conta os novos elementos gráficos inseridos.

Vamos começar adicionando um comportamento extra ao que Opcao3 faz. Selecione o GameObject e, na aba Inspector, ao final da lista de parâmetros do componente Button, clique sobre o botão com o sinal de mais (+):

No campo que se abrir (na imagem a seguir, em destaque azul), referencie o GameObject Seta. Clique sobre a caixa de seleção “No function” (em destaque verde), selecione a opção GameObject e, em seguida, SetActive(bool). A caixa de seleção (em destaque laranja) deverá ser deixada vazia.


Ao se clicar no botão “Sobre o jogo”, será realizada, além da ocultação de TelaInicial e da ativação de TelaSobre, a desativação do objeto Seta, para que ele não fique sendo exibido em sobreposição ao texto de créditos do game.

Para que a seta seja exibida após voltarmos à tela inicial do menu, primeiramente iremos desativar TelaInicial e ativar TelaSobre, selecionando-os individualmente na aba Hierarchy e os ativando/desativando via aba Inspector. Após isso, selecione o GameObject Opcao3 (subordinado a TelaSobre) e renomeie-o para “Opcao4”, para não criarmos confusão com nomes iguais.

Ainda com Opcao4 selecionado, na aba Inspector, iremos realizar os mesmos passos que fizemos agora há pouco com Opcao3, em relação à inserção de uma ação extra a ser executada ao se clicar no botão, referenciando o objeto Seta e alterando o parâmetro GameObject.SetActive. Desta vez, contudo, a caixa de seleção (em destaque laranja) deverá ser selecionada, para que a seta volte a ser exibida.

Na aba Hierarchy, selecione TelaSobre e, na aba Inspector, desative-o. Faça o inverso com o GameObject TelaInicial, reativando-o. Agora iremos programar, de fato, o botão “Escolher personagem” para que haja a modificação efetiva do personagem.

Primeiro, na aba Hierarchy, vamos selecionar o objeto PersonagemDesenho. Na aba Inspector, adicione um componente do tipo Selecionar Personagem. Seu parâmetro Personagem A deverá receber a imagem de nome “carrinho” e Personagem B a imagem de nome “perua”.

Agora, selecione o GameObject Opcao2. Na aba Inspector, no final da listagem de parâmetros do elemento Button, pressione duas vezes o botão com o sinal de menos (-) até que a lista de ações de On Click () esteja vazia:

Clique uma vez sobre o botão com o sinal de mais (+), referencie o objeto PersonagemDesenho e, por fim, selecione a ação SelecionarPersonagem.TrocarPersonagem:


Por fim, para darmos um toque de dinamicidade ao processo de escolha do personagem em nosso menu inicial, vamos reaproveitar a animação que criamos para as caixinhas de presente para dar destaque ao veículo a ser escolhido.

Na aba Project, abra as pastas Assets, Multimidia e, por fim, Animacoes. Clique e arraste o elemento “AnimacaoPresente.anim” para a aba Hierarchy, em direção ao objeto PersonagemDesenho:


Veja que, além de um novo item controlador de animação surgir na pasta de animações (PersonagemDesenho.controller), o GameObject PersonagemDesenho recebeu um componente Animator pré-configurado com o parâmetro Controller adequado, pronto para começar a balançar por aí de forma bem animada.

Que tal ver na prática todas essas alterações que criamos até o momento? Para isso, vá até a aba Game e pressione Play para iniciar a simulação de execução:

Ao término da simulação, pressione novamente o botão Play. Salve a cena (menu File, Save) e o projeto (menu File, Save Project) antes de fechar o Unity.

Próximos passos

Embora tenhamos codificado e programado diversos elementos para efetivar a troca do personagem (que já ocorre no menu de forma satisfatória), ainda não temos de forma plenamente funcional a perua andando pelos caminhos de nosso game. 

Em nosso próximo encontro, concluiremos a inserção dessa nova companheira de jornada pelas estradas e florestas de nosso game, realizaremos alguns ajustes pontuais no projeto e... finalizaremos a construção de Motorista da Pesada!


Nosso próximo texto já encontra-se disponível, continue conosco nessa jornada de conhecimento e fique ligado sempre aqui no GameBlast!

Revisão: Ives Boitano

Entendo videogames como sendo uma expressão de arte e lazer e, também, como uma impactante ferramenta de educação. No momento, doutorando em Sistemas da Informação pela EACH-USP, desenvolvendo jogos e sistemas desde 2020. Se quiser bater um papo comigo, nas redes sociais procure por @RodrigoGPontes.
Este texto não representa a opinião do GameBlast. Somos uma comunidade de gamers aberta às visões e experiências de cada autor. Escrevemos sob a licença Creative Commons BY-SA 3.0 - você pode usar e compartilhar este conteúdo desde que credite o autor e veículo original.