Programação jogos de computador pode ser o trabalho mais desafiador tecnicamente (e possivelmente o mais bem pago) que um programador podem ter. Jogos de nível superior exigem o melhor de programadores e computadores.
Visual básico 6 agora foi completamente ignorado como uma plataforma para programação de jogos. (Nunca foi realmente um. Mesmo nos "bons e velhos tempos", programadores de jogos sérios nunca usavam uma linguagem de alto nível como o VB 6 porque você simplesmente não conseguia entender desempenho de ponta que a maioria dos jogos exige.) Mas o simples jogo "Tic Tac Toe" é uma ótima introdução à programação um pouco mais avançada do que "Olá Mundo!"
Esta é uma ótima introdução a muitos dos conceitos fundamentais de programação, pois combina técnicas, incluindo:
- O uso de matrizes. Os marcadores X e O são mantidos em matrizes separadas e as matrizes inteiras são passadas entre as funções para acompanhar o andamento do jogo.
- Usando gráficos de nível VB 6: O VB 6 não oferece grande capacidade gráfica, mas o jogo é uma boa introdução ao que está disponível. Grande parte do restante desta série é uma exploração de como o GDI +, a próxima geração de gráficos da Microsoft, substitui os gráficos de nível VB 6.
- Usando cálculos matemáticos para controle de programa: O programa usa módulo inteligente (Mod) e número inteiro cálculos de divisão usando as matrizes de marcador de dois jogos para determinar quando uma "vitória" de três elementos ocorreu.
A classe de programação neste artigo talvez esteja um pouco além do nível inicial, mas deve ser boa para programadores "intermediários". Mas vamos começar no nível básico para ilustrar alguns dos conceitos e começar com o seu Visual básico carreira de programação de jogos. Mesmo os alunos mais avançados do que isso podem achar que é um pouco desafiador obter os objetos da forma correta.
Como Jogar Tic Tac Toe
Se você nunca jogou Jogo da velha, aqui estão as regras. Dois jogadores se alternam ao colocar Xs e Os no campo de jogo 3 x 3.
Antes do jogo começar, os dois jogadores precisam concordar sobre quem irá primeiro e quem marcará seus movimentos com qual símbolo. Após o primeiro movimento, os jogadores colocam suas marcas alternadamente em qualquer célula vazia. O objetivo do jogo é ser o primeiro jogador com três marcas em uma linha horizontal, diagonal ou vertical. Se não houver células vazias e nenhum jogador tiver uma combinação vencedora, o jogo será empatado.
Antes de iniciar qualquer codificação real, é sempre uma boa idéia alterar os nomes dos componentes que você usa. Depois de começar codificação, o nome será usado automaticamente pelo Visual Basic para que você queira que seja o nome correto. Usaremos o nome do formulário frmTicTacToe e também mudaremos a legenda para "Sobre o jogo da velha".
Com o formulário estabelecido, use o controle de caixa de ferramentas de linha para desenhar uma grade 3 x 3. Clique na ferramenta de linha e desenhe uma linha onde desejar. Você precisará criar quatro linhas dessa maneira e ajustar seu comprimento e posição para fazê-las parecerem corretas. O Visual Basic também possui algumas ferramentas convenientes no menu Formatar que ajudarão. Esta é uma ótima chance de praticar com eles.
Além da grade de jogo, precisaremos de alguns objetos para os símbolos X e O que serão colocados na grade. Como existem nove espaços na grade, criaremos uma matriz de objetos com nove espaços, chamados elementos no Visual Basic.
Existem várias maneiras de fazer praticamente tudo no ambiente de desenvolvimento do Visual Basic, e criar matrizes de controle não é exceção. Provavelmente, a maneira mais fácil é criar o primeiro rótulo (clique e desenhe exatamente como a ferramenta de linha), nomeie-o, defina todos os atributos (como Font e ForeColor) e faça cópias dele. O VB 6 perguntará se você deseja criar uma matriz de controle. Use o nome lblPlayGround para o primeiro rótulo.
Para criar os outros oito elementos da grade, selecione o primeiro objeto de rótulo, defina a propriedade Index como zero e pressione CTRL + C (cópia). Agora você pode pressionar CTRL + V (colar) para criar outro objeto de etiqueta. Quando você copia objetos como este, cada cópia herdará todas as propriedades, exceto o Índice, da primeira. O índice aumentará em um para cada cópia. Essa é uma matriz de controle, porque todas elas têm o mesmo nome, mas diferentes valores de índice.
Se você criar a matriz dessa maneira, todas as cópias serão empilhadas umas sobre as outras no canto superior esquerdo do formulário. Arraste cada etiqueta para uma das posições da grade de reprodução. Verifique se os valores do índice são seqüenciais na grade. A lógica do programa depende disso. O objeto label com o valor de índice 0 deve estar no canto superior esquerdo e o rótulo inferior direito deve ter o índice 8. Se os rótulos cobrirem a grade de reprodução, selecione cada rótulo, clique com o botão direito do mouse e selecione Enviar para trás.
Como existem oito maneiras possíveis de ganhar o jogo, precisaremos de oito linhas diferentes para mostrar a vitória na grade de jogo. Você usará a mesma técnica para criar outra matriz de controle. Primeiro, desenhe a linha, nomeie-linWin e defina a propriedade Index como zero. Em seguida, use a técnica copiar e colar para produzir mais sete linhas. A ilustração a seguir mostra como definir os números de índice corretamente.
Além dos objetos de etiqueta e linha, você precisa de alguns botões de comando para jogar e mais etiquetas para marcar pontos. As etapas para criá-las não são detalhadas aqui, mas esses são os objetos que você precisa.
Botão dois objetos:
- cmdNewGame
- cmdResetScore
Objeto de quadro fraPlayFirst contendo dois botões de opção:
- optXPlayer
- optOPlayer
Objeto de quadro fraScoreBoard contendo seis rótulos. Somente lblXScore e lblOScore são alterados no código do programa.
- lblX
- lblXScore
- lblO
- lblOScore
- lblMinus
- lblColon
Por fim, você também precisa do objeto de rótulo lblStartMsg para 'mascarar' o botão cmdNewGame quando não deve ser clicado. Isso não é visível na ilustração abaixo porque ocupa o mesmo espaço no formulário do botão de comando. Talvez você precise mover o botão de comando temporariamente para desenhar esse rótulo no formulário.
Até o momento, nenhuma codificação VB foi feita, mas finalmente estamos prontos para isso.
Inicialização
Agora você finalmente começa a codificar o programa. Se você ainda não o fez, pode fazer o download do código-fonte a seguir, conforme a operação do programa é explicada.
Uma das primeiras decisões de design a serem tomadas é como acompanhar o 'estado' atual do jogo. Em outras palavras, quais são os Xs e Os atuais na grade de jogo e quem se move a seguir. O conceito de 'estado' é crítico em muita programação e, em particular, é importante na programação do ASP e ASP.NET para a Web
Existem várias maneiras de fazer isso, por isso é uma etapa crítica na análise. Se você estava resolvendo esse problema por conta própria, convém desenhar um fluxograma e experimentar opções diferentes com 'papel de rascunho' antes de iniciar qualquer codificação.
Nossa solução usa duas "matrizes bidimensionais" porque isso ajuda a acompanhar o 'estado', simplesmente alterando os índices da matriz nos loops de programa. O estado do canto superior esquerdo estará no elemento da matriz com o índice (1, 1), o canto superior direito estará em (1, 3), o canto inferior direito em (3,3) e assim por diante. As duas matrizes que fazem isso são:
iXPos (x, y)
e
iOPos (x, y)
Há várias maneiras diferentes de fazer isso e a solução final do VB.NET nesta série mostra como fazê-lo com apenas uma matriz unidimensional.
A programação para converter essas matrizes em decisões de vitória do jogador e exibições visíveis no formulário estão na próxima página.
Você também precisa de algumas variáveis globais da seguinte maneira. Observe que eles estão no código Geral e Declarações do formulário. Isso os torna "nível do módulo" variáveis que podem ser referenciadas em qualquer lugar do código para este formulário. Para obter mais informações, consulte Noções básicas sobre o escopo das variáveis na Ajuda do Visual Basic.
Existem duas áreas em que as variáveis são inicializadas em nosso programa. Primeiro, algumas variáveis são inicializadas enquanto o formulário frmTicTacToe está sendo carregado.
Subformulário Privado_Load ()
Segundo, antes de cada novo jogo, todas as variáveis que precisam ser redefinidas para os valores iniciais são atribuídas em uma sub-rotina de inicialização.
Sub InitPlayGround ()
Observe que a inicialização de carregamento do formulário também chama a inicialização do playground.
Uma das habilidades críticas de um programador é a capacidade de usar os recursos de depuração para entender o que o código está fazendo. Você pode usar este programa para tentar:
- Percorrendo o código com a tecla F8
- Configurando um monitoramento de variáveis-chave, como sPlaySign ou iMove
Definir um ponto de interrupção e consultar o valor das variáveis. Por exemplo, no loop interno da inicialização:
lblPlayGround ((i - 1) * 3 + j - 1) .Caption = ""
Observe que este programa mostra claramente por que é uma boa prática de programação manter os dados em matrizes sempre que possível. Se você não possuía matrizes neste programa, teria que escrever um código como este:
Line0.Visible = False
Line1.Visible = False
Line2.Visible = False
Line3.Visible = False
Line4.Visible = False
Line5.Visible = False
Line6.Visible = False
Line7.Visible = False
em vez disso:
Para i = 0 a 7
linWin (i) .Visible = False
Proximo eu
Fazendo um movimento
Se qualquer parte do sistema pode ser considerada "o coração", é a sub-rotina lblPlayGround_Click. Essa sub-rotina é chamada toda vez que um jogador clica na grade de jogo. (Os cliques devem estar dentro de um dos nove elementos lblPlayGround.) Observe que esta sub-rotina possui um argumento: (Índice como número inteiro). A maioria das outras 'sub-rotinas de eventos', como cmdNewGame_Click (), não. O índice indica em qual objeto do rótulo foi clicado. Por exemplo, o índice conteria o valor zero no canto superior esquerdo da grade e o valor oito no canto inferior direito.
Depois que um jogador clica em um quadrado na grade do jogo, o botão de comando para iniciar outro jogo, cmdNewGame, é "ativado", tornando-o visível. O estado desse botão de comando funciona duas vezes, porque também é usado como uma variável de decisão booleana posteriormente no programa. O uso de um valor de propriedade como variável de decisão geralmente é desencorajado, porque se for necessário alterar o programa (por exemplo, para fazer o botão de comando cmdNewGame visível o tempo todo), o programa falhará inesperadamente porque você talvez não se lembre de que também é usado como parte do programa lógica. Por esse motivo, é sempre uma boa ideia pesquisar no código do programa e verificar o uso de qualquer coisa que você altera ao fazer a manutenção do programa, até mesmo os valores das propriedades. Este programa viola a regra parcialmente para explicar esse ponto e em parte porque esse é um trecho de código relativamente simples, onde é mais fácil ver o que está sendo feito e evitar problemas posteriormente.
Uma seleção de jogadores de um quadrado de jogo é processada chamando a sub-rotina GamePlay com Index como argumento.
Processando a mudança
Primeiro, você verifica se um quadrado desocupado foi clicado.
Se lblPlayGround (xo_Move) .Caption = "" Então
Quando tivermos certeza de que é uma jogada legítima, o contador de jogadas (iMove) é incrementado. As próximas duas linhas são muito interessantes, uma vez que traduzem as coordenadas da escala unidimensional Se o componente lblPlayGround for de matriz para índices bidimensionais que você pode usar no iXPos ou no iOPos. A divisão mod e número inteiro (a barra invertida) são operações matemáticas que você não usa todos os dias, mas aqui está um ótimo exemplo que mostra como elas podem ser muito úteis.
Se lblPlayGround (xo_Move) .Caption = "" Então
iMove = iMove + 1
x = Int (xo_Move / 3) + 1
y = (xo_Move Mod 3) + 1
O valor xo_Move 0 será convertido para (1, 1), 1 para (1, 2)... 3 a (2, 1)... 8 a (3, 3).
O valor em sPlaySign, uma variável com escopo de módulo, controla qual jogador fez a jogada. Depois que as matrizes de movimentação são atualizadas, os componentes da etiqueta na grade de reprodução podem ser atualizados com o sinal apropriado.
Se sPlaySign = "O", então
iOPos (x, y) = 1
iWin = CheckWin (iOPos ())
Outro
iXPos (x, y) = 1
iWin = CheckWin (iXPos ())
Fim se
lblPlayGround (xo_Move) .Caption = sPlaySign
Por exemplo, quando o X player clicar no canto superior esquerdo da grade, as variáveis terão os seguintes valores:
A tela do usuário mostra apenas um X na caixa superior esquerda, enquanto o iXPos possui 1 na caixa superior esquerda e 0 em todas as outras. O iOPos tem 0 em cada caixa.
Os valores mudam quando o jogador O clica no quadrado central da grade. Agora, o iOPos mostra um 1 na caixa central, enquanto a tela do usuário mostra um X no canto superior esquerdo e um O na caixa central. O iXPos mostra apenas o 1 no canto superior esquerdo, com 0 em todas as outras caixas.
Agora que você sabe onde um jogador clicou e qual jogador clicou (usando o valor em sPlaySign), tudo o que você precisa fazer é descobrir se alguém ganhou um jogo e descobrir como mostrar isso no exibição.
Encontrando um vencedor
Após cada movimento, a função CheckWin verifica a combinação vencedora. O CheckWin funciona adicionando cada linha, em cada coluna e em cada diagonal. O rastreamento das etapas através do CheckWin usando o recurso de depuração do Visual Basic pode ser muito educativo. Encontrar uma vitória é uma questão de primeiro, verificar se três 1s foram encontrados em cada uma das verificações individuais na variável iScore e, em seguida, retornando um valor de "assinatura" exclusivo no Checkwin que é usado como índice de matriz para alterar a propriedade Visible de um elemento no linWin matriz de componentes. Se não houver vencedor, o CheckWin conterá o valor -1. Se houver um vencedor, a exibição é atualizada, o placar é alterado, uma mensagem de parabéns é exibida e o jogo é reiniciado.
Vamos passar por uma das verificações em detalhes para ver como funciona. Os outros são parecidos.
'Verifique as linhas para 3
Para i = 1 a 3
iScore = 0
CheckWin = CheckWin + 1
Para j = 1 a 3
iScore = iScore + iPos (i, j)
Próximo j
Se o iScore = 3, então
Função de saída
Fim se
Proximo eu
A primeira coisa a notar é que o primeiro contador de índice i faz uma contagem regressiva das linhas, enquanto o segundo j conta através das colunas. O loop externo, então simplesmente se move de uma linha para a seguinte. O loop interno conta os 1s na linha atual. Se houver três, você terá um vencedor.
Observe que você também acompanha o número total de quadrados testados na variável CheckWin, que é o valor passado quando essa função é encerrada. Cada combinação vencedora terminará com um valor único no CheckWin de 0 a 7, que é usado para selecionar um dos elementos na matriz de componentes linWin (). Isso torna a ordem do código na função CheckWin também importante! Se você moveu um dos blocos de código de loop (como a acima), a linha errada seria traçada na grade de jogo quando alguém vencer. Experimente e veja!
Detalhes de acabamento
O único código ainda não discutido é a sub-rotina para um novo jogo e a sub-rotina que redefinirá a pontuação. O restante da lógica do sistema facilita a criação dessas. Para iniciar um novo jogo, basta chamar a sub-rotina InitPlayGround. Como uma conveniência para os jogadores, pois o botão pode ser clicado no meio de um jogo, você pede confirmação antes de prosseguir. Você também solicita confirmação antes de reiniciar o placar.