Criando um jogo "Genius"

Bem vindos a mais um tutorial aqui do blog! Hoje nós vamos criar no Visual Studio, um jogo chamado "Genius" (Também conhecido como "Siga o som") que consiste em revelar uma determinada sequência que você deverá seguir, e a medida que você vai tendo sucesso, o tamanho da sequência vai aumentando, até que você erre!
O resultado final deste tutorial será esse:



Neste tutorial você vai estudar os seguintes itens: Listas, exibição de conteúdo de listas, classe randômica, espera utilizando a biblioteca threading, execução de áudio, métodos, ferramenta de menu e manipulação de picturebox.

Design do formulário:
O design será bem simples, mas caso queira colocar algo a mais, vá em frente!
Abra um novo projeto em seu Visual Studio em aplicação de formulário e mude algumas propriedades do formulário, tais como:

Texto >> "Jogo Genius"
StartPosition >> CenterScreen
MaximizeBox, MinimizeBox e ControlBox >> False
BackColor >> A seu gosto
Size >> A seu gosto e necessidade

Agora arraste para o formulário quatro pictureboxes:

Nome: pbCor
*Cor é o nome da cor da picturebox que vamos colocar, por exemplo: pbAzul
Size: A seu gosto
Tag: O nome da cor que vai representar, por exemplo: "Amarelo"
Enabled: False
BackColor: A cor da picturebox num tom mais escuro.
As cores que teremos no jogo serão: Vermelho, amarelo, azul e verde.
Essas cores iniciais eu deixei como: DarkRed, Goldenrod, Blue e DarkGreen.
Será então através dessas pictureboxes que as sequências ocorrerão.

Também arraste uma label com o nome de "lblPontos" para registrar os pontos do jogador.
A label pode ter o texto "Pontos" e o tamanho de fonte que você desejar.

Por fim, arraste o objeto "MenuStrip"com o nome de "mstMenu". Na opção "type here" escolha "menu list" e coloque o nome de "mstArquivo" com o texto "Arquivo". Crie três sub-menus: "Iniciar", "Sobre" e "Sair" cada um com as tags referentes à sua opção.
O menu deve estar assim:


Seu formulário deve estar mais ou menos assim:


Criando as variáveis:
Com o formulário pronto, vamos agora iniciar a codificação do nosso jogo.
Dê F7 no teclado para abrir a janela de código.

Vamos criar nossas variáveis globais primeiramente:
Crie duas listas do tipo "string", uma com o nome de "SequenciaCores" e a outra com o nome "SequenciaJogador".
Essas listas serão responsáveis por guardar as cores sorteadas da sequência. Como as listas se auto-ajustam à quantidade de objetos inseridos nela, seria a melhor opção para armazenar uma sequência aleatória, visto que o jogador pode alcançar quantidades de sequências variáveis à cada jogada.
A outra lista é para o jogador, assim será guardado as sequências que ele realizou, para no final checarmos se os conteúdos de ambas listas são iguais.

Crie agora um vetor de strings com o nome de "cores" e o inicie com quatro strings: "Vermelho, amarelo, azul e verde".
Vai ser através deste vetor que a randomização sorteará uma cor aleatória para a sequência.

Crie também duas variáveis do tipo string que irão armazenar as cores atuais que foram exibidas/clicadas, tanto para o jogador, quanto para a sequência em si, dessa forma, poderemos ter um controle de qual cor está sendo exibida para criar o efeito de "ascender a luz da cor indicada", assim como no jogo original.

Agora vamos definir duas variáveis do tipo inteiro, uma guardará os pontos que o jogador está fazendo, e a outra guardará de forma dinâmica o índice das listas, para então checarmos se o jogador está acertando a sequência.

E por fim, teremos uma variável do tipo bool chamada "podeJogar" que irá gerenciar o momento que o jogador poderá imitar a sequência, pois, enquanto a mesma está sendo mostrada, ele não poderá clicar nas pictureboxes.

Você também pode instanciar neste momento a classe Random:



Sorteando uma cor:
Vamos então criar um método privado, sem retorno com o nome de "SortearCores" sem passagem de parâmetros.
Armazene dentro da variável "atualCor" um elemento aleatório do vetor "cores".
Para fazer essa randomização, utilize o método "Next" através da instância "rdn" dentro do vetor "cores".
Agora adicione à lista "sequenciaCores" o valor de "atualCor".

Vamos então mostrar ao jogador qual cor está piscando através da sequência. Para isso, criaremos um outro método privado com o nome de "MostrarCor', tendo como parâmetro uma string que irá determinar qual é a cor atual da sequência a ser mostrada.

Dentro deste método utilizaremos a estrutura "switch..case" para definirmos qual é a cor atual a ser exibida, através do parâmetro de string chamado "atualCor".
Antes porém, referencie no ínício do código as seguintes bibliotecas: "System.Threading" e "System.Media".
A primeira biblioteca permite que possamos utilizar o método estático "Sleep" da classe "Thread" para criarmos um tipo de "espera" no código, assim podemos exibir as cores das sequências uma de cada vez, aguardando sempre a exibição da anterior, para que possamos exibir a próxima, evitando de criar um bug de todas as cores serem exibidas ao mesmo tempo.
A outra biblioteca nos permitirá utilizar sons do próprio sistema Windows para que possamos colocar áudio nas exibições de cores.

Volte para o método de mostrar a cor e utilize a estrutura "switch...case" para verificar qual é a cor atual a ser exibida.
Dependendo do seu parâmetro "atualCor", altere a propriedade "BackColor" da picturebox correspondente.
Para as cores mais leves eu deixei como "Red, "Cyan", Lime" e "Yellow".
Após trocar a propriedade de cor, vamos executar um som com o seguinte comando: "SystemSounds.Exclamation.Play();"
Onde há "Exclamation" no código, você pode trocar por uma das propriedades de som que aparecerão ao utilizar a classe "SystemSounds".

Após exibir uma cor mais clara que a da atual na tela, precisamos retornar à cor anterior. Para isso, utilize o método estático "Sleep" da classe "Thread" e passe como argumento o tempo de espera (em milissegundos). Eu deixei 800 que é uma boa espera, mas você pode alterar este valor conforme a sua necessidade.
Para que este comando execute corretamente, antes dele utilize o método estático "DoEvents" da classe "Application", para que de fato, ocorra a espera em thread.
Depois disso, não se esqueça do "break" para finalizar a execução dentro da estrutura.
Este método, por fim, deve estar assim:




Feito isto, retorne ao método "SortearCores" e inicie um laço "foreach" que percorra completamente a lista "sequenciaCores", para que assim, seja exibida a sequência corretamente, quantas vezes forem necessárias.
O único comando dentro deste laço é o de chamar o método "MostrarCor" passando como argumento a variável de passagem do laço.
Para que tenha uma espécie de "espera" entre essas passagens de cores, utilize novamente os comandos "Application.DoEvents" e "Thread.Sleep" e passe como 250 o argumento de espera (ou um número que você deseje).

Após exibir todas as cores que foram sorteadas aleatoriamente em sequência, é hora de deixar o jogador jogar, portanto, fora do laço, chame um método chamado "PodeJogar" que vamos criar a seguir.

No fim, o método de sorteio deve estar desta forma:




Realizando sequências:
Agora que já foi mostrado ao jogador qual é a sequência de cores que ele deve realizar, vamos aprontar o programa para que a pessoa possa jogar.

Primeiramente criaremos o método "PodeJogar" sem retorno e sem parâmetros.
Este método será bem simples: Basta criar um laço foreach que percorra os controles do tipo "Picturebox" em seu formulário, para que possa deixar a propriedade "Enabled" de todas as pictureboxes em "true", fazendo com que o jogador possa clicar nessas pictureboxes para jogar.
Após o laço, deixe a variável "podeJogar" como true:


Neste momento é a vez do jogador acertar a sequência, ele poderá fazer isso clicando sobre as pictureboxes, então, vamos criar o método de referência de clique do jogador para servir como chamada para as quatro pictureboxes.
Este método deve ser privado, sem retorno, o nome pode ser "CliqueReferencia_Click" com dois argumentos, uma variável do tipo "object" chamada "sender" e outra do tipo "EventArgs" chamada "e".
Volte para seu formulário, selecione as quatro pictureboxes, vá na aba "events" e em "Click" selecione o método que acabamos de criar, desta forma, não importa qual dessas quatro pictureboxes você clique, todas elas chamarão este mesmo método.

Dentro do método, crie uma variável do tipo "Picturebox" com o nome de "pic" e armazene a referência da picturebox através do casting de sua referência dentro de "sender".

Nesse momento, verifique com uma estrutura de decisão se a variável "podeJogar" está verdadeira.
Dentro dessa estrutura, armazene dentro da variavél "atualJogador" a tag referente da picturebox clicada (não se esqueça de convertê-la para string!)
Também deixe em "false" a variável "podeJogar".
Depois, adicione dentro da lista "sequenciaJogador" a variável "atualJogador" e chame o método "MostrarCor" passando como argumento justamente "atualJogador".

Após exibir a cor, verifique se o conteúdo da lista "sequenciaCores" é igual ao conteúdo da lista "sequenciaJogador" no índice atual de verificação.
Este índice inicia em zero, e a medida que o jogador vai pressionando as cores, este índice vai recebendo um incremento. Este índice será referenciado através da variável "indexLista".

Então se os conteúdos das listas forem iguais, a pessoa acertou a cor, portanto, incremente o índice da lista e a variável "pontos", atualizando também sua label de exibição. Também devemos checar se o jogador já acertou toda a sequência atual, essa verificação ocorrerá através de um método chamado "ChecarFinal" que será criado a seguir, porém, já chame este método.

Caso o conteúdo das listas no índice atual forem diferentes, a pessoa errou a sequência e o jogo se encerrará, mostrando uma mensagem com um MessageBox.

Este método deve estar assim:



Agora vamos criar o método "ChecarFinal" que verifica se a sequência de cores já foi realizada pelo jogador, ou seja, se o índice das listas é igual ao tamanho da lista "sequenciaCores".
Se forem iguais, significa que o jogador já realizou a sequência atual, então sua vez acabou, portanto, zere o índice das listas, limpe a lista do jogador (para que na próxima rodada ele possa reiniciar a sequência) e chame o método de sortear cores novamente.
Para dar um tempo antes de sortear a cor, utilize o sleep em 450.

Caso o jogador ainda não tenha terminado a sequência, deixe true novamente a variável "podeJogar".

O método estará assim:


Por fim, esta será a programação e lógica do jogo em si. Podemos programar agora as ações que cada opção do menu irá realizar.

Funções do Menu:
Criaremos um método chamado "MenuReferencia_Click" e passaremos como argumento um tipo "object" e EventArgs" igual fizemos com o método de clique.
Dentro deste método também defina uma referência da opção a se clicada através da classe "ToolStripMenuItem" e utilizando-se da estrutura "switch..case" verifique através da tag desta referência qual opção foi clicada.

Caso tenha sido a opção com tag "Inicio", o jogo vai ser iniciado, ou seja, "pontos" deve ser zero, "podeJogar" deve ser false, sequenciaCores e sequeciaJogador devem estar limpas, e a label que exibe os pontos deve ser atualizada, não se esquecendo, obviamente, que o método "SortearCores" deve ser chamado pela primeira vez (se for o início do jogo).

Caso seja a tag "Sobre" apenas exiba uma mensagem sobre o jogo e o desenvolvedor.
Para não atrapalhar o fluxo do jogo, certifique-se que a variável "podeJogar" esteja verdadeira.

Por fim, caso a tag seja "Sair", pergunte realmente se o jogador deseja abandonar o jogo, e caso sim, feche a aplicação.

Este método deve ser chamado através do evento "Click" dos objetos de "Arquivo".

Deve estar assim:



Finalização:
Então pessoal, chegamos em mais um final de tutorial no blog! Teste sua aplicação e veja que ela roda perfeitamente.
Espero que tenham gostado deste tutorial, e até o próximo!

Aula em vídeo:

Comentários