Caso essa seja a primeira vez que você interage com conteúdos de nossa série, sinta-se à vontade para juntar-se a nós em uma jornada repleta de aprendizados sobre o universo do desenvolvimento de jogos. Por meio do uso da plataforma Unity, estamos elaborando diferentes projetos práticos de programação de games, desde sua concepção até o jogo pronto de fato.
No momento, estamos elaborando o terceiro game de nossa série: trata-se de Consultório do Dr. Tratanildo, uma excêntrica aventura ambientada em um consultório médico tridimensional, cujo estilo de gameplay presta homenagem a clássicos como Dr. Mario (Nintendo, 1990) e Pac-Man (Namco, 1980).
Independentemente se você já tem conhecimentos prévios de programação ou não, por meio das atividades práticas propostas você terá a oportunidade de aprender a tirar do papel aquele jogo que sempre sonhou em tornar realidade.
A partir do primeiro texto da série, são abordados desde a instalação e a configuração da ferramenta Unity em nossos computadores até os tópicos que envolvem a inserção, configuração e codificação de elementos visuais, sonoros, textuais e de lógica para cada jogo desenvolvido.
Aproveite a oportunidade e venha conosco para que possamos, juntos, seguir nessa trilha rumo a novos conhecimentos!
Tempo decrescente
Uma das vantagens de termos codificado a maior parte das variáveis de controle das fases no encontro anterior é a flexibilidade que teremos, daqui em diante, na implementação das funcionalidades que serão necessárias para que as regras do jogo possam “sair do papel”.
Hoje, por exemplo, iremos implementar, dentro do método void Update() de ControllerFase, códigos úteis para o controle do tempo em uma fase, para a exibição dos segundos restantes no Canvas e, ao término da contagem regressiva, a correta exibição dos elementos da tela de derrota em cena. Para o correto funcionamento de todas essas funcionalidades, lançaremos mão de diferentes elementos referenciados pelas variáveis que criamos.
Que tal, então, abrirmos nosso projeto para retomarmos sua edição? No Unity Hub, clique duas vezes sobre o item referente ao projeto Consultório do Dr. Tratanildo. Na interface inicial do editor, na aba Project, abra a pasta Assets, Scenes e, por fim, clique duas vezes no ícone da cena ConsultorioScene.
Na aba Project, abra a pasta Assets e, em seguida, Scripts. Clique duas vezes sobre o ícone do script ControllerFase para abri-lo no Visual Studio.
Role a tela de edição do script no Visual Studio para baixo até encontrar os códigos void Start() e void Update(). Hoje nossas edições no código se concentrarão em suas estruturas.
Para iniciarmos a codificação do controlador de tempo das fases, dentro das chaves do método void Update(), insira o seguinte trecho de código:
// Controle do tempo
if (Geral.ModoDeJogoCorrente == "BuscaMedicamentos" || Geral.ModoDeJogoCorrente == "Labirinto")
{
tempoRestante -= Time.deltaTime;
barraInfoAcoes.SetActive(true);
textoTempoRestante.text = Mathf.FloorToInt(tempoRestante / 60).ToString("00") + ":" + Mathf.FloorToInt(tempoRestante % 60).ToString("00");
if (tempoRestante < 0)
{
Geral.ModoDeJogoCorrente = "Perdeu";
tempoRestante = 0;
barraInfoAcoes.SetActive(false);
controladorLabirinto.gameObject.SetActive(false);
visualizacaoLabirinto.SetActive(false);
telaDerrota.SetActive(true);
}
}
Para entendermos quais as ações que serão tomadas no game por meio do código recém-inserido, precisamos recordar alguns conceitos importantes da construção de nosso projeto até o momento.
Em encontros anteriores, elaboramos dois scripts controladores da aventura: ControllerFase, que é o arquivo que estamos editando no momento, e Geral, responsável por informações úteis a todo o jogo, mesmo fora do ambiente principal do consultório.
Em Geral introduzimos a variável ModoDeJogoCorrente, que permitirá aos códigos dos scripts do game saberem em qual “momento” da aventura o jogador está. Inicialmente, predizemos a utilização dos seguintes valores para ModoDeJogoCorrente:
- “Menu”: valor a ser utilizado quando o jogador ainda estiver com a tela de menu (a ser desenvolvida) em destaque na tela;
- "Consultorio": valor a ser utilizado enquanto Doutor Tratanildo está em seu consultório antes de se iniciar um tratamento com paciente;
- "BuscaMedicamentos": valor a ser utilizado enquanto o médico está buscando medicamentos nas prateleiras de seu consultório para o tratamento de um paciente que já está deitado sobre o leito;
- "Labirinto": valor a ser utilizado enquanto Tratanildo está operando o maquinário com o paciente deitado sobre o leito, já com as pílulas de saúde dentro do corpo do enfermo em tratamento.
Em nossa aventura, somente fará sentido termos um decréscimo constante do tempo restante de tratamento enquanto houver um paciente sendo tratado, ou seja, nos momentos em que o valor ModoDeJogoCorrente for igual a “BuscaMedicamentos” ou “Labirinto”.
A partir dessa verificação, serão realizadas as seguintes ações pelo código:
- Decréscimo constante do valor de tempo restante (tempoRestante -= Time.deltaTime);
- Exibição da barra de informações na tela (barraInfoAcoes.SetActive(true));
- Atualização constante dos valores de tempo apresentados na barra de informações (modificação do valor de textoTempoRestante.text).
Sobre esse último, para a correta exibição do tempo no formato “<minutos>:<segundos>” em tela, foi necessária a tomada de uma interessante sucessão de ações devido a algumas características dos códigos que utilizamos.
Entendendo o mostrador de tempo
Em ControllerFase, a variável tempoRestante representa quantos segundos ainda restam para a conclusão do tratamento. Seu valor está sendo armazenado em formato float, ou seja, como um valor numérico com casas decimais (ex.: 145,37 segundos). Para sua exibição em tela, realizamos a seguinte sequência de operações:
- O valor dos minutos foi calculado a partir da divisão de tempoRestante por sessenta (quantidade de segundos presentes em um minuto), sendo tomado apenas a parte inteira dessa divisão, por meio da função Math.FloorToInt, função essa que retorna o maior inteiro igual ou inferior ao valor informado.
Por exemplo, para 255 segundos, realizando-se a divisão por sessenta, teríamos 4,25 minutos; com o uso de Math.FloorToInt, obteríamos o valor 4:
- Embora com o uso de Mathf.FloorToInt(tempoRestante / 60) obtemos o valor dos minutos restantes, para sua correta exibição com o uso de, no mínimo, dois dígitos em tela, realizamos sua conversão para texto (string) utilizando a função ToString(“00”). Dessa forma, valores como, por exemplo, 2 minutos serão exibidos como “02”.
- Já o valor dos segundos foi calculado a partir da obtenção do resto da divisão de tempoRestante por sessenta, operação representada pelo código (tempoRestante % 60). As conversões realizadas para a obtenção do valor inteiro dos segundos e a formatação em dois dígitos foram semelhantes às realizadas para os minutos, por meio da utilização das funções Math.FloorToInt e ToString("00").
- Para a composição final do texto a ser exibido em tela, o valor concedido a textoTempoRestante.text é a concatenação do valor dos minutos formatado, o sinal de dois pontos (“:”) e o valor dos segundos formatado.
Todas essas operações foram condensadas em uma linha de código só. Como as diferentes ações permitidas pela programação de scripts podem ser poderosas, não?
Passam-se os minutos
Por fim, dentro do código inserido, temos um subconjunto de operações a serem realizadas apenas se o tempo já tiver se esgotado, ou seja, se o valor de tempoRestante for menor do que zero.
De forma resumida, são essas as ações que serão tomadas pelo game ao se constatar que o jogador não conseguiu tratar o paciente a tempo:
- Altera-se o valor da variável ModoDeJogoCorrente do script Geral para “Perdeu”, interrompendo, dentre outras ações, a subtração do tempo restante e o controle de outros módulos que dependam de o jogo estar no modo BuscaMedicamentos ou no modo Labirinto;
- Zera-se o valor de tempoRestante;
- Desativam-se o controle do labirinto (controladorLabirinto), sua visualização no Canvas (visualizacaoLabirinto) e a barra de informações em tela (barraInfoAcoes);
- Exibe-se ao jogador a tela de game over de nossa aventura (telaDerrota).
Agora que acrescentamos essa importante funcionalidade em nosso projeto, que tal testá-la? Antes de retornarmos ao editor do Unity, dentro das chaves do método void Start(), acrescente o seguinte trecho de código:
Geral.ModoDeJogoCorrente = "Labirinto";
tempoRestante = 125;
Os valores informados servirão apenas para testarmos o game no momento, sendo que, posteriormente, iremos substituí-los pelos valores definitivos para o início das fases.
Salve o script, feche o Visual Studio e retorne ao editor do Unity. Experimente a execução do game indo à aba Game e pressionando o ícone do botão Play:
Note como, após nossas intervenções no código, o mostrador de tempo restante apresenta os minutos e segundos de forma correta em tela.
Ao se aguardar até o término da contagem regressiva, você poderá presenciar a realização da sequência de ações que planejamos para o momento da derrota no jogo:
Interrompa a simulação do game, clicando novamente sobre o ícone do botão Play e retornando à exibição da aba Scene. Não se esqueça de salvar a cena (menu File, opção Save) e o projeto (menu File, opção Save Project) antes de fechar o editor.
Próximos passos
Com o extenso conjunto de ações que realizamos nos encontros anteriores, tanto em relação ao conjunto de codificações concretizado quanto sobre a correta configuração e disposição de elementos em cena, estamos cada vez mais próximos de termos um jogo tridimensional funcional em mãos.
Em nossos próximos encontros, daremos sequência à implementação das regras do game por meio de edições nos scripts controladores da aventura.
Nosso próximo encontro será no dia 30 de março. Até mais! Fique sempre ligado nas novidades do GameBlast!
Revisão: Ives Boitano