Show do Zecão - Um Jogo de perguntas e respostas


Você conhece o jogo Show do milhão ? Sabia que foi feito em Visual Basic ? (pelo menos até a versão 2). Temos ai um exemplo bem sucedido de uma aplicação feita em Visual Basic.

Tudo bem , o jogo não tem muitos recursos gráficos e, é, em sua essência, até um jogo muito simples. Mas foi um sucesso de vendas, mostrando que agradou o público e que atingiu o objetivo.

Já pensou se você tivesse a mesma ideia ( e o mesmo marketing) $$$

Bem, não fique frustrado.

Vou mostrar como criar um jogo igualzinho ao Show do Milhão  e aproveitar para abordar alguns tópicos importantes como: 

Veja agora as principais telas(na verdade todas as telas) do sensacional jogo - Show do Zecão :

frmintroducao: A tela de abertura

frmsplash: A tela inicial

frmnome: A tela de identificação do usuário

A tela de apresentação dos valores das rodadas

A tela de perguntas

A tela de pergunta mostrando o acionamento da ajuda com os agentes microsoft : Genie e Merlin em ação

A tela de encerramento do jogo

O funcionamento do jogo  - Show do Zecão - é idêntico ao jogo Show do Milhão e será dissecado neste artigo (o jogo foi feito em algumas horas).

Por isso não espere por recursos gráficos de primeira , nem efeitos com animação (eu não usei...). Os arquivos de som também foram gerados  no gravador de som do windows.

Apesar de tudo isto, o jogo funciona bem, mostrando que você pode desenvolver sistemas comerciais  sem ser um mestre em VB,  e, se você tiver um bom conhecimento geral poderá ganhar - Um milhão de reais...

A lógica do jogo

Bem a lógica do jogo e responder as perguntas e a medida que você for acertando você vai em frente avançado para fase seguinte  até alcançar a última fase com a pergunta que vale 1.000.000,00 de reais.  Mas o que interessa para nós é o seguinte: 

  1. Onde estão armazenadas essas perguntas ? 

  2. Como o programa seleciona cada pergunta e exibe as opções de resposta ?

  3. Como o sistema verifica se a pergunta esta certa ou errada ?

Vamos responder todas essas perguntas explicando-as em detalhes. A primeira é fácil: As perguntas estão armazenadas em um banco de dados Access . A estrutura da tabela que contém as perguntas é muito importante e você logo vai saber por que.

Temos um banco de dados Access chamado Perguntas.mdb que contém uma tabela chamada Perguntas com a seguinte estrutura:

Assim uma pergunta será visualizada na tabela assim:

  Pergunta resp1 resp2 resp3 resp4 respostacerta utilizada Nivel
1 Quanto é dois mais dois ?

3

5

4

6

3

N

A

Percebeu que com esta estrutura basta posicionar o ponteiro no registro para extrair a Pergunta , as opções de Resposta e a coluna com a Resposta Certa para comparar com a resposta indica pelo usuário. 

As colunas pergunta , resposta1, resposta2,  resposta3 e  resposta4 , você preenche quando cadastra a pergunta no banco de dados . O nosso jogo já tem algumas perguntas cadastradas e também permitirá a você cadastrar mais perguntas.

A  coluna - respostacerta - irá armazenar o número da questão correta, desta forma , para saber se o usuário escolheu a opção correta basta comparar a opção clicada com o número da coluna correspondente a Pergunta

A coluna - ja_utilizada - indica se a pergunta já foi utilizada ou não , desta forma nunca repetiremos a mesma pergunta duas vezes no mesmo jogo. Quando o jogo começa todas as  colunas  referentes ao campo - ja_utilizada  - possuem o valor N e após o usuário acertar a pergunta o campo - ja_utilizada - é atualizado para S , com isto esta pergunta não será mais selecionada no jogo em curso.

A coluna - tipo -  indica a que fase a pergunta pertence , com isto podemos filtrar perguntas referentes a uma determinada fase . Fazemos isto utilizando as consultas Seleção  SQL.

Assim para filtrar as perguntas por fase podemos usar uma consulta com a seguinte sintaxe:

SELECT perguntas.numero, perguntas.pergunta, perguntas.resposta1, perguntas.resposta2, perguntas.resposta3, perguntas.resposta4, perguntas.ja_utilizada, perguntas.tipo
FROM perguntas
WHERE (((perguntas.tipo)="A"))
ORDER BY perguntas.numero;

Esta consulta seleciona as perguntas , opções de resposta , resposta certa e o tipo da pergunta da tabela Perguntas quando a pergunta for do tipo A ( perguntas da primeira fase) e as ordena por número da pergunta.

Obs: Basta alterar a letra na cláusula Where para B , C ou D para obter consultas para outras fase ; cada uma corresponde a fase 2 , 3 e 4. Teremos portanto quatro consultas nomeadas como : Fase1 , Fase2 , Fase3 e Fase4 que selecionarão as perguntas referentes a cada fase do jogo.

Agora que você tem uma visão geral vamos passear pelas telas do jogo e abordar os aspectos mais importantes utilizados para criar o Show do Zecão.

A Introdução 

Ao iniciar o projeto a tela de introdução será exibida e cada linha da mensagem será exibida compassadamente na tela . Quando a última mensagem (Boa Sorte) for exibida , após alguns segundos o formulário - frmintroducao - será fechado e será exibido o formulário , vemos abaixo o formulário em tempo de desenho do projeto. Como disse eu não me preocupei com os efeitos visuais , por isso usei recursos simples apenas para ilustrar as possibilidades. 

Neste formulário foram usados controles:

1-) Timers - Para controlar a exibição das mensagens.

2-) Labels - Contém os dizeres de cada frase

3-) Image - Para exibir o logo Show do Zecão.

Você vai perceber que ao iniciar o projeto uma música começa a tocar continuamente conforme as frases vão sendo exibidas na tela.

Como obtemos este recurso ?

Estamos usando arquivos do tipo WAV , portanto , para obter o recurso de tocar um arquivo WAV continuamente usaremos uma API declarada em um módulo . Eis a declaração:

Public Declare Function sndPlaySound Lib "winmm.dll" Alias "sndPlaySoundA" (ByVal lpszSoundName As String, ByVal uFlags As Long) As Long

Então para tocar um arquivo wav basta chamar a função informando sua localização e nome, assim:

Call sndPlaySound("c:\ashowzecao\certa.wav", 0)

Isto irá tocar o arquivo certa.wav localizado no diretório c:\ashowzecao uma única vez, para que o arquivo seja continuamente tocado devemos usar as constantes :

Const SND_ASYNC = &H1          'modo assíncrono. toca musica sem parar
Const SND_LOOP = &H8            

Você deve declarar estas constantes na seção General Declarations do formulário. A chamada da função , nestes casos, deverá ser feita usando estas constantes, assim:

Call sndPlaySound("c:\show do zecao\entrada.wav", SND_ASYNC + SND_LOOP)

Assim o código que exibe toca a música para o formulário frmintroducao é:

Private Sub Timer2_Timer()
  Call sndPlaySound("c:\show do zecao\entrada.wav", SND_ASYNC + SND_LOOP)
  Timer2.Enabled = False
End Sub

Estamos usando o controle Timer - Timer2  -  para acionar o arquivo entrada.wav .  Um controle Timer é usado para processar tarefas em um determinado intervalo de tempo. 

O arquivo é acionado  após  quase um segundo da carga do formulário. Este tempo é definido na propriedade Interval do controle Timer2 . A  propriedade Interval é definida em milisegundos , assim cada 1000 corresponde a 1 segundo.

Atribuímos o valor a propriedade assim:

Timer2.interval = 500       ´ou definimos a propriedade no próprio controle  assim:

Após a chamada a função SndPlaySound desabilitamos o controle Timer2 - ( Timer2.enabled= False ) , evitamos assim que a função seja chamada novamente após decorrido o tempo definido em Interval.

O outro controle Timer - Timer1 - foi usado para , da mesma forma , exibir na tela as frases em intervalos de tempo distintos. O código é o seguinte:

Private Sub Timer1_Timer()
If contador = 3 Then
  Label1.Visible = True
End If
If contador = 13 Then
  Label2.Visible = True
End If
If contador = 21 Then
  Label3.Visible = True
End If
If contador = 31 Then
  Image1.Visible = True
End If
If contador = 38 Then
  Label4.Visible = True
  End If
If contador = 50 Then
  Call sndPlaySound("c:\ashowzecao\semsom.wav", 0)
  Unload Me
  frmSplash.Show vbModal
End If
contador = contador + 1
End Sub

Observe que usamos a variável contador , que é incrementada a intervalos de tempo definido em Timer1.interval . Usamos o arquivo chamado semsom.wav para interromper a musica acionada em entrada.wav.

Demos uma possibilidade de o usuário interromper a exibição de todas as frases na tela e a música exibindo o formulário frmSplash . Basta ele clicar no formulário para que isto ocorra. O código é:

Private Sub Form_Click()
   Call sndPlaySound("c:\ashowzecao\semsom.wav", 0)
   Unload Me
   frmSplash.Show vbModal
nd Sub

Agora observe o código do evento Load do formulário.

Private Sub Form_Load()
contador = 0
If Dir(App.Path & "\show.ini") <> "" Then
  valortempo = ReadINI("Geral", "Tempo", App.Path & "\show.ini")
  valorajuda = ReadINI("Geral", "Ajuda", App.Path & "\show.ini")
  atualizaperguntas = ReadINI("Geral", "Atualiza", App.Path & "\show.ini")
Else
  MsgBox " O ARQUIVO DE CONFIGURAÇÃO - NÃO FOI LOCALIZADO !. OS VALORES PADRÕES SERÃO ASSUMIDOS !"
  valortempo = 40
  valorajuda = 2
  atualizaperguntas = "SIM"
End If
End Sub

Este código além de inicializar o contador, também procura pelo arquivo Show.ini lendo o seu conteúdo e atribuindo os valores definidos no arquivo a variáveis  de configuração.

Os arquivos INI eram muito usados no Windows 3.X e ainda podem ser utilizados para determinadas tarefas.

No nosso jogo usamos o arquivo Show.INI para configurar algumas preferências do usuário . São Elas :

O que é um arquivo INI ?

Um arquivo INI é um arquivo texto usado para armazenar/fornecer configurações pessoais para sistemas/usuários;

Um arquivo INI é um arquivo com dados externo ao programa principal e esta formatado em : Seções(FileName) , Entradas e Valores :

[Seçao1]
entrada=valor
entrada=valor
entrada=valor
[Seção2]
entrada=valor
entrada=valor

Um exemplo de arquivo INI é o WIN.INI cuja estrutura mostramos em parte a seguir:

[windows]
load=
run=
NullPort=None
device=HP DeskJet 690C,HPDSKJTB,LPT1:
SingleClickSpeed=067614

[Desktop]
Wallpaper=(None)
TileWallpaper=0
WallpaperStyle=2
Pattern=120 49 19 135 225 200 140 30

No nosso caso estamos usando o arquivo SHOW.INI para guardar algumas preferências do usuário. Sua estrutura é a seguinte:

[Geral]
Tempo=50
Ajuda=2
Atualiza=SIM

Como fazemos para acessar e/ou alterar os valores em um arquivo INI ?

Boa pergunta !

Para fazer isto usamos duas API's do Windows , vamos apresentá-las:

1-) API usada para ler os arquivos INI . Geralmente você faz esta declaração em um módulo:

Declare Function GetPrivateProfileString Lib "kernel32" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nsize As Long, ByVal lpFileName As String) As Long

2-) API usada para escrever em uma arquivo INI. Geralmente você faz esta declaração em um módulo

Declare Function WritePrivateProfileString Lib "kernel32" Alias "WritePrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As Any, ByVal lpString As Any, ByVal lpFileName As String) As Long

Agora basta escrever duas funções que usam estas API´s , uma para ler e outra para escrever. Elas estão prontas abaixo:

1-) Função - ReadINI - lê um arquivo INI. Precisa de três parâmetros : O nome da Seção , o nome da Entrada e o nome do Arquivo INI.

Public Function ReadINI(Secao As String, Entrada As String, Arquivo As String)
  'Arquivo=nome do arquivo ini
  'Secao=O que esta entre []
  'Entrada=nome do que se encontra antes do sinal de igual

 Dim retlen As String
 Dim Ret As String
 Ret = String$(255, 0)
 retlen = GetPrivateProfileString(Secao, Entrada, "", Ret, Len(Ret), Arquivo)
 Ret = Left$(Ret, retlen)
 ReadINI = Ret
End Function

2-) A função - WriteINI - escreve em um arquivo INI. Precisa de quatro parâmetros : o nome da Seção , o nome da Entrada ,  o nome do Texto ( Valor ) e o nome do arquivo INI.

Public Sub WriteINI(Secao As String, Entrada As String, Texto As String, Arquivo As String)
  'Arquivo=nome do arquivo ini
  'Secao=O que esta entre []
  'Entrada=nome do que se encontra antes do sinal de igual
  'texto= valor que vem depois do igual

  WritePrivateProfileString Secao, Entrada, Texto, Arquivo
End Sub

No nosso caso para Ler os valores do arquivo SHOW.INI usamos o seguinte código:

valortempo = ReadINI("Geral", "Tempo", App.Path & "\show.ini")
valorajuda = ReadINI("Geral", "Ajuda", App.Path & "\show.ini")
atualizaperguntas = ReadINI("Geral", "Atualiza", App.Path & "\show.ini")

As variáveis valortempo, valorajuda e atualizaperguntas irão armazenar os valores lidos do arquivo Show.ini através da função ReadINI.

Para escrever em um arquivo INI alterando os valores das entradas: Tempo, Ajuda e Atualiza , usamos o seguinte código:

Call WriteINI("Geral", "Tempo", txttempo.Text, App.Path & "\show.ini")
Call WriteINI("Geral", "Ajuda", txtajuda.Text, App.Path & "\show.ini")
Call WriteINI("Geral", "Atualiza", txtatualiza.Text, App.Path & "\show.ini")

Os valores são informados nas caixas de texto txttempo.txt , txtajuda.text e txtatualiza.text . Como isso lemos e escrevemos em arquivos INI.

O formulário de perguntas e respostas

Para não tornar o artigo muito longo e enfadonho vamos direto ao módulo mais importante do projeto : o arquivo frmperguntas.

É na carga deste formulário que geramos as perguntas, aguardamos a resposta do  usuário, verificamos se o tempo não acabou, solicitamos a ajuda, verificamos se a resposta esta correta, se o usuário resolveu parar, enfim as principais ações do jogo.

Então vamos por partes...

A seção General Declarations do formulário frmperguntas é a seguinte: Nele definimos as variáveis que serão visíveis em todo o formulário.

Dim rsperg As Recordset
Dim selecao As Integer
Dim sql As String
Dim tempo As Integer
Dim Genie As IAgentCtlCharacterEx  'inicializa o ator
Const DataAtor = "genie.acs"            'define o caminho para o agente que voce vai usar
Const dataAtor2 = "merlin.acs"         'define o caminho para o agente que voce vai usar
Dim Merlin As IAgentCtlCharacter
Const SND_ASYNC = &H1                 'modo asíncrono. toca musica sem parar
Const SND_LOOP = &H8 '

1-) Exibindo a barra de progresso e o valor das variáveis globais

O código do evento Load do formulário frmperguntas é os seguinte:

Private Sub Form_Load()

lblusuario.Caption = NomeUsuario

selecao = 1
tempo = valortempo
progbar1.Max = valortempo
progbar1.Min = 0
lbltempo.Caption = tempo

randomize

gera_perguntas

End Sub

As variáveis NomeUsuario , selecao , valortempo  e tempo são variáveis globais definidas no nosso arquivo de módulo show.bas.

Progbar1 é o nome da nossa barra de progresso que indica o tempo que resta para responder a pergunta.

Como implementamos essa barra de progresso ?

A barra de progresso - Progbar1 - usada no projeto possui as propriedades definidas na figura ao lado.

A propriedade Max e Min são definidas em tempo de execução como:

progbar1.Max = valortempo
progbar1.Min = 0

Estes  valores são definidos no arquivo INI. Assim o usuário pode aumentar/diminuir o valor do tempo de resposta.

Também usamos uma label acima da barra de progresso que exibe o valor numérico do tempo que resta para responder a pergunta. Este valor é definido em :

 lbltempo.Caption = tempo

A instrução Randomize irá permitir que as perguntas sejam geradas de forma aleatórias.

Como queremos que a barra de progresso reflita o tempo restante usamos um controle Timer com propriedade interval definida como sendo igual a  1000 ( 1000 = 1 segundo ), com isso , a cada segundo o evento Timer é acionado. Incluímos então no evento Timer o código a seguir:

Private Sub Timer2_Timer()
Dim aumento As Integer

progbar1.Value = progbar1.Value + 1
tempo = tempo - 1
lbltempo.Caption = tempo

If progbar1.Value = valortempo Then
   Call sndPlaySound("c:\ashowzecao\tempo.wav", 0)
   Unload Me
   frmparar.Show vbModal
End If

End Sub

Com ele incrementamos o valor da barra de progresso - progbar1 - em uma unidade ( progbar1.Value + 1) e decrementamos o valor da variável tempo de 1 ( tempo - 1 ) exibindo assim o valor número decrescendo .

Se o valor da barra de progresso for igual ao tempo máximo definido ( valortempo )  um aviso sonoro é emitido , o formulário é descarregado e o formulário frmparar exibe quanto o usuário ganhou até aquele instante.

2-) Gerando as perguntas 

Como já dissemos as perguntas do nosso jogo estão armazenadas em um banco de dados Access ( usei a versão 2000 ). O nome do banco de dados é - Perguntas.mdb.  A tabela que contém as questões chama-se Perguntas. 

Quando o formulário frmperguntas for chamado, o banco de dados já deverá ter sido aberto. Na verdade ele foi aberto  quando o usuário forneceu o nome e clicou no botão Jogar. O código é o seguinte:

Set ws = DBEngine.Workspaces(0)
Set db = ws.OpenDatabase(App.Path & "\perguntas.mdb")

Já deu para perceber que estamos usando DAO . Por que ? Por que é mais simples e rápido.

Temos também armazenadas no banco de dados quatro consultas referentes as perguntas de cada fase do jogo. Assim para a fase 1 temos a consulta :

SELECT perguntas.numero, perguntas.pergunta, perguntas.resposta1, perguntas.resposta2, perguntas.resposta3, perguntas.resposta4, perguntas.respostacerta, perguntas.ja_utilizada, perguntas.tipo
FROM perguntas
WHERE (((perguntas.tipo)="A"))
ORDER BY perguntas.numero;

Para a fase 2 temos a consulta :

SELECT [perguntas].[numero], [perguntas].[pergunta], [perguntas].[resposta1], [perguntas].[resposta2], [perguntas].[resposta3], [perguntas].[resposta4], [perguntas].[respostacerta], [perguntas].[ja_utilizada], [perguntas].[tipo]
FROM perguntas
WHERE ((([perguntas].[tipo])="B"))
ORDER BY [perguntas].[numero];

ate a fase 4. Então basta selecionarmos as perguntas de cada fase usando cada consulta pertinente. Como não queremos repetir uma pergunta iremos selecionar somente as perguntas que ainda não foram utilizadas ( ja_utilizada="N"). 

Private Sub gera_perguntas()
Dim posicao As Long

If Fase = 1 Then
   sql = "Select * from Fase1 where ja_utilizada='N'"
ElseIf Fase = 2 Then
   sql = "Select * from Fase2 where ja_utilizada='N'"
ElseIf Fase = 3 Then
   sql = "Select * from Fase3 where ja_utilizada='N'"
ElseIf Fase = 4 Then
   sql = "Select * from Fase4 where ja_utilizada='N'"
End If

Set rsperg = db.OpenRecordset(sql, dbOpenDynaset)
rsperg.MoveLast
rsperg.MoveFirst

If rsperg.RecordCount > 0 Then
  posicao = rsperg.RecordCount
Else
  posicao = 1
End If

questao = Int((posicao * Rnd) + 1)
Move questao

lblpergunta.Caption = rsperg.Fields(1)

For i = 0 To 3
   lblresp(i).Caption = rsperg.Fields(i + 2)
Next

End Sub

A seguir geramos um recordset do tipo Dynaset chamado rsperg com a consulta sql . Usamos as propriedades MoveLast e MoveFirst para movermos o ponteiro do para fim do arquivo e para o inicio de forma a obter um valor correto para a quantidade de registros ( Recordcount ) do recordset.

Sabendo a quantidade de registros , na verdade estou sabendo a quantidade de perguntas que tenho. Agora podemos gerar as questões. 

3 -) Como gerar perguntas Aleatórias ?

Para gerar perguntas aleatórios utilizamos a função Rnd em conjunto com a instrução Randomize.

A função Rnd gera números pseudo aleatórios. Pseudo aleatórios por que parece que são aleatórios mas na verdade não são.  Para um número ser aleatório ele não pode ser previsível e isto não ocorre com a função Rnd

 Esta função tem a seguinte sintaxe:

Rnd[(numero)]               -   Número é um valor do tipo Single. Os valores retornados são:

Se número for Rnd irá gerar
menor que zero O mesmo número sempre . O número será usado como semente.(seed)
Maior que zero O próximo número na sequência.
Igual a zero O mais recente número gerado.
Não fornecido O próximo número aleatório na sequência.

Observe que:
  1. A função Rnd gera um valor menor que 1 e maior que ou igual a zero.
  2. O Valor do número determina como a função Rnd gera o número aleatório.
  3. Para qualquer número usado como semente inicial a sequência gerada será sempre a mesma. 
  4. A instrução Randomize se um argumento , inicializa o gerador aleatório com uma semente(seed) baseada no relógio do sistema.

Cada vez que a função Rnd é chamada,  um novo valor é gerado. Este valor é sempre menor que 1 mas maior ou igual a zero , temos então que :    0 <= Rnd < 1

Então para gerar números em uma faixa que você deseja, é o só usar a fórmula:

Exemplo:

Ao usar a função Rnd temos um problema ,  cada vez que o seu projeto rodar os valores retornados pela função Rnd serão sempre os mesmos.

Isto teria um efeito indesejável não é mesmo ? Como contornar este problema ?

Para evitar isto usamos a instrução Randomize. Ela inicializa o gerador de números aleatórios com base no relógio do sistema(pois não usamos argumentos na instrução).

Portanto para evitar gerar a mesma sequência usamos a instrução Randomize antes de chamar a função Rnd.  Podemos fazer isto somente uma vez.(Por isso colocamos a instrução Randomize no evento do formulário) 

Se você precisar repetir uma determinada sequência de números , basta chamar a função Rnd com um argumento negativo e imediatamente usar  a instrução  Randomize com um argumento numérico indicando a semente que deseja usar. Assim :

'Faz o VB iniciar usando um parâmetro em Randomize.
Rnd -1
'Faz o VB usar o valor 123 como ponto de partida ( seed ).
Randomize 123
Vejamos então o código da rotina que irá gerar as perguntas:

Private Sub gera_perguntas()
Dim posicao As Long

If Fase = 1 Then
  sql = "Select * from Fase1 where ja_utilizada='N'"
ElseIf Fase = 2 Then
  sql = "Select * from Fase2 where ja_utilizada='N'"
ElseIf Fase = 3 Then
  sql = "Select * from Fase3 where ja_utilizada='N'"
ElseIf Fase = 4 Then
  sql = "Select * from Fase4 where ja_utilizada='N'"
End If

Set rsperg = db.OpenRecordset(sql, dbOpenDynaset)
rsperg.MoveLast
rsperg.MoveFirst

If rsperg.RecordCount > 0 Then
   posicao = rsperg.RecordCount
Else
    msgbox 'Não há perguntas cadastradas para esta fase ! "  

    exit sub

End If

questao = Int((posicao * Rnd) + 1)
Move questao

lblpergunta.Caption = rsperg.Fields(1)

For i = 0 To 3
   lblresp(i).Caption = rsperg.Fields(i + 2)
Next

End Sub

Logo no início temos a montagem da instrução SQL que irá gerar o recordset com as perguntas. Como temos 4 fases , conforme a fase do jogo iremos selecionar perguntas usando as consultas armazenadas no banco de dados . Então montamos a instrução assim:

 sql = "Select * from Fase1 where ja_utilizada='N'"

Aqui selecionamos todos os registros gerados pela consulta Fase1 quando a pergunta ainda foi utilizada. Fazemos isto para cada fase do jogo.

A seguir geramos o recordset e movimentamos o ponteiro para o final do arquivo retornando ao inicio logo a seguir. Com isto teremos a quantidade de registro deste recordset.

Set rsperg = db.OpenRecordset(sql, dbOpenDynaset)
rsperg.MoveLast
rsperg.MoveFirst

A seguir apenas verificamos se realmente existem perguntas no recordset gerado , se não houver perguntas avisamos o usuário e saímos da rotina:

If rsperg.RecordCount > 0 Then
   posicao = rsperg.RecordCount
Else
    msgbox 'Não há perguntas cadastradas para esta fase ! "  

    exit sub

End If

Agora vamos gerar um número aleatório entre 1 e a quantidade de registros que existe no recordset ( posição). Com isto sempre estaremos trabalhando com as perguntas existentes no arquivo. Com o número gerado movemos a ponteiro para o registro com este número.

questao = Int((posicao * Rnd) + 1)
Move questao

Finalmente com o ponteiro no registro , extraímos os campos referentes a pergunta e as opções de resposta. Usamos o objeto Fields , onde rsperg.Fields(1) refere-se ao segundo campo do recordset ( o indíce zero é o primeiro campo ). 

lblpergunta.Caption = rsperg.Fields(1)

For i = 0 To 3
   lblresp(i).Caption = rsperg.Fields(i + 2)
Next

4-) Pedindo Ajuda

 

O usuário pode pedir Ajuda durante o jogo ( a quantidade de vezes que ele pode pedir ajuda você configura no arquivo SHOW.INI , lembra ? ) . Aqui usamos os agentes microsoft - Genie e Merlin. (Você pode usar outros...). 

 

Então quando o usuário clica no botão ajuda temos o seguinte código:

 

Private Sub lblopcao2_Click()
If lblopcao2.Caption = "NÃO" Then
   lblresp(selecao - 1).ForeColor = vbYellow
   lblopcao1.Caption = "Parar"
   lblopcao2.Caption = "Ajuda"
Else
   If Fase < 4 Then       ' não carrega na ultima pergunta (não tem ajuda)
     If Not estacarregado Then
        ajuda = ajuda + 1
         If genio Then
            Agent1.Characters.Load "Genie", DataAtor     'carrega o ator
            Set Genie = Agent1.Characters("Genie")        'define o ator que vai atuar
            estacarregado = True
            Genie.LanguageID = &H409                          'define a linguagem
            Genie.MoveTo 590, 240
            Genie.Show                                             'faz o ator aparecer
         End If
         If magico Then
            Agent1.Characters.Load "Merlin", dataAtor2    'carrega o ator
            Set Merlin = Agent1.Characters("Merlin")        'define o ator que vai atuar
            estacarregado = True
            Merlin.LanguageID = &H409                          'define a linguagem
            Merlin.MoveTo 490, 240
            Merlin.Show                                             'faz o ator aparecer
        End If
      End If  ' esta carregado
   End If
End If
End Sub

 

Se o botão estiver exibindo a palavra Ajuda , então , a primeira coisa que verificamos é a fase do jogo em que estamos.

 

Se a fase do jogo não for a última fase ( if fase < 4 ) então verificamos se o agente já esta carregado (if Not estacarregado ); 

 

Se o agente não estiver carregado incrementamos a variável ajuda de uma unidade e verificamos se o agente ainda pode ser carregado ( if genio then/ if magico then ).  

 

As variáveis públicas genio e magico são variáveis boleanas definidas no módulo do projeto e de início possuem o valor True ;

 

Quando o número de vezes que o usuário pediu ajuda for maior que a quantidade de ajuda definida no arquivo Show.ini ( If ajuda > valorajuda Then ) então genio ou magico recebem o valor False não podendo ser mais carregados.

 

O código para carga do agente é o seguinte:

 

            Agent1.Characters.Load "Genie", DataAtor    'carrega o ator
            Set Genie = Agent1.Characters("Genie")      
 'define o ator que vai atuar
            estacarregado = True
            Genie.LanguageID = &H409                       
  'define a linguagem
            Genie.MoveTo 590, 240
            Genie.Show                                              
'faz o ator aparecer

Para recebe Ajuda você deve clicar no agente desejado para ele 'falar' a resposta correta para você (você pode implementar o efeito sonoro de voz para  agente ... ). O código é o seguinte:

Private Sub Agent1_Click(ByVal CharacterID As String, ByVal Button As Integer, ByVal Shift As Integer, ByVal x As Integer, ByVal y As Integer)
If CharacterID = "Merlin" Then
   If ajuda > valorajuda Then
      magico = False
   End If
   fala = "A resposta correta é a ...: "
   fala = fala & rsperg(6)
   Merlin.Speak fala
End If
If CharacterID = "Genie" Then
   If ajuda > valorajuda Then
      genio = False
   End If
   fala = "A resposta correta é a ... "
   fala = fala & rsperg.fields(6)
   Genie.Speak fala
End If
End Sub

Ao clicar em um agente , verificamos qual o agente que você clicou ( CharacterID = "Merlin" ) e , se o número de ajudas solicitado for maior que o permitido definimos a variável magico ou genio , conforme o agente , para False de forma que este agente não poderá ser mais carregado.

A seguir  fazermos o agente 'falar' ( Genie.Speak fala ) a resposta correta. A resposta correta é o sétimo campo do recordset rsperg ( rsperg.fields(6) ) . 

5-) Verificando a resposta correta

 

Quando o usuário seleciona uma opção e clica no botão SIM , o código a seguir entra em ação :

 

Private Sub lblopcao1_Click()
   If lblopcao1.Caption = "SIM" Then
         If selecao = rsperg(6) Then
             atualiza_registro
             Call sndPlaySound("c:\ashowzecao\certa.wav", 0)
             Pergunta = Pergunta + 1
             If Fase >= 4 Then
                Unload Me
                frmparar.Show vbModal
             End If
             If Pergunta > 5 Then
                     Fase = Fase + 1
                     Pergunta = 1
              End If
              Unload Me
              frmvalores.Show vbModal
         Else
              lblresp(rsperg(6) - 1).ForeColor = vbWhite
              lblresp(selecao - 1).ForeColor = vbYellow
              Refresh
              Call sndPlaySound("c:\ashowzecao\errada.wav", 0)
              Sleep 4000
              Unload Me
              frmparar.Show vbModal
        End If
   Else
        lblresp(selecao - 1).ForeColor = vbYellow
   End If
   If lblopcao1.Caption = "Parar" Then
           Call sndPlaySound("c:\ashowzecao\temcerteza.wav", 0)
            Sleep 3000
            Unload Me
            frmparar.Show vbModal
   End If
End Sub

Ao clicar no botão SIM , verificamos se a seleção é igual a resposta correta (selecao =  rsperg.fields(6)) ; se a resposta for correta atualizamos o registro marcando-o como já utilizado através da rotina:

Private Sub atualiza_registro()
   rsperg.Edit
  rsperg!ja_utilizada = "S"
  rsperg.Update
End Sub

A  seguir  emitimos o aviso sonoro (Call sndPlaySound("c:\ashowzecao\certa.wav", 0) ) , incrementamos a variável pergunta de uma unidade ( pergunta = pergunta + 1 )  , verificamos se estamos na última fase ( em caso positivo descarregamos o formulário e o jogo é encerrado ). 

Se a variável pergunta for maior que 5 ,  retornamos ao valor 1 e mudamos de fase :

             If Pergunta > 5 Then
                     Fase = Fase + 1
                     Pergunta = 1
              End If

Se o usuário errar ou escolher parar o jogo , o código a seguir é executado:

              lblresp(rsperg(6) - 1).ForeColor = vbWhite
              lblresp(selecao - 1).ForeColor = vbYellow
              Refresh
              Call sndPlaySound("c:\ashowzecao\errada.wav", 0)
              Sleep 4000
              Unload Me
              frmparar.Show vbModa

Mostramos qual a resposta correta (   lblresp(rsperg(6) - 1).ForeColor = vbWhite ) ,  emitimos o aviso sonoro ,  usamos uma pausa de 4 segundos ( sleep 4000 ) - declarada no módulo do projeto) e o jogo é encerrado.

Com isso vou terminando por aqui as explicações sobre este jogo.( O código dos demais formulários não apresentam nada de novo).

A intenção foi mostrar as principais rotinas envolvidas na criação de um projeto de um jogo usando banco de dados e alguns efeitos . Se você quiser e tiver tempo pode incrementar o jogo com telas , sons e efeitos tornando-o um mais amigável  e mais eficiente.

Se não quiser pode jogar a vontade com a vantagem que você pode cadastrar as suas perguntas e respostas  e alterar alguns parâmetros como tempo de resposta e quantidade de ajudas. 

Percebeu que não é preciso muito para você um criar um projeto viável comercialmente e  ganhar uns trocados... ?

Agora é com você...

Obs: Eu vou disponibilizar somente os códigos fontes do jogo , os arquivos de som você vai ter que gerar para poder usar. Infelizmente os arquivos WAV ocupam muito espaço , que para mim é precioso.

O jogo completo esta no   Super DVD Visual Basic

Para baixar os fontes clique aqui :   Show do Zecão  ( 154 KB )

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências:


José Carlos Macoratti