IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Tutoriel Gdi+ : programmez un jeu de Pacman complet en VBA

Image non disponible


précédentsommairesuivant

XIII. Gestion des options de jeu

XIII-A. Stockage des options

Les options de jeu sont des valeurs modifiables par le joueur.
Il faut donc les stocker quelque part pour ne pas avoir à les redéfinir à chaque jeu.

On a plusieurs possibilités pour stocker ces valeurs d'options :

  1. Etant sous Excel on pourrait les stocker dans une feuille.
    Mais ça impliquerait une sauvegarde du fichier Excel complet à chaque modification d'option et c'est un peu lourd.
  2. On peut les stocker dans un fichier texte.
    Gérer un fichier ini se fait facilement à l'aide des fonctions WritePrivateProfileString et GetPrivateProfileString de la bibliothèque kernel32.dll.

On va donc se créer une fonction de lecture et une fonction d'écriture d'option dans le fichier ini.
Ce fichier s'appelera config.ini et sera placé dans un sous-dossier config que nous créons dès maintenant dans le répertoire du projet.

Dans le module ModFunctions, ajoutez les déclarations en en-tête :

Déclaration pour gestion de fichier ini
Sélectionnez
' Déclarations pour fichier ini
#If VBA7 Then
Private Declare PtrSafe Function WritePrivateProfileString Lib "kernel32" Alias _
        "WritePrivateProfileStringA" (ByVal lpApplicationName As String, _
        ByVal lpKeyName As Any, ByVal lpString As Any, ByVal lpFileName As String) As Long
Private Declare PtrSafe 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
#Else
Private 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
Private Declare Function GetPrivateProfileString Lib "kernel32" Alias _
        "GetPrivateProfileStringA" (ByVal lpApplicationName As Any, ByVal lpKeyName As Any, _
        ByVal lpDefault As String, ByVal lpReturnedString As String, ByVal nSize As Long, _
        ByVal lpFileName As String) As Long
#End If

Puis ajoutez ces deux fonctions :

Fonctions de lecture/écriture de fichier ini
Sélectionnez
'------------------------------------------------------------------------
' Lecture de la valeur d'une clé dans un fichier ini
'------------------------------------------------------------------------
Public Function ReadOption(pOption As String, Optional pDefault As String) As String
Dim lRet As Long
Dim lData As String
Dim lSize As Long
lData = Space$(8192)
lSize = 8192
lRet = GetPrivateProfileString("Options", pOption, pDefault, lData, lSize, ThisWorkbook.path & "\config\config.ini")
If lSize > 0 Then
    ReadOption = Left$(lData, lRet)
Else
    ReadOption = ""
End If
End Function
            
'------------------------------------------------------------------------
' Ecriture de la valeur d'une clé dans un fichier ini
'------------------------------------------------------------------------
Public Function WriteOption(pOption As String, Optional pValue As String) As Boolean
Dim lRet As Long
Dim lSize As Long
If pValue = "" Then
    lRet = WritePrivateProfileString("Options", pOption, 0&, ThisWorkbook.path & "\config\config.ini")
Else
    lRet = WritePrivateProfileString("Options", pOption, pValue, ThisWorkbook.path & "\config\config.ini")
End If
WriteOption = (lRet <> 0)
End Function

ReadOption pour lire une valeur.
WriteOption pour écrire une valeur.

Inutile de créer le fichier config.ini à la main, il sera créé automatiquement à la première écriture d'option.
Par contre le dossier dans lequel on écrit le fichier ini doit exister.

XIII-B. Les variables des options

Nos options devront être accessibles par tous les écrans.
En effet les touches paramétrées serviront aussi bien dans l'écran de jeu que dans les autres écrans (pour validation, choix dans le menu…).

Nous allons donc créer des variables dans le module de données partagées clSharedData.

Déclaration des variables dans clSharedData pour options de jeu
Sélectionnez
' Code des touches
Public ToucheBas As Long
Public ToucheHaut As Long
Public ToucheDroite  As Long
Public ToucheGauche  As Long
Public ToucheValid  As Long
' Nombre de fantômes
Public NbFantomes As Long
' Joystick utilisé
Public JoyNum As Long
' Bouton de validation du joystick
Public JoyButton As Long

Nous retrouvons les options définies au début :

  • le nombre de fantômes ;
  • les différentes commandes clavier et joystick.

XIII-C. Chargement des options

Nos options devront être chargées au lancement du jeu, dans la procédure RunGame de l'objet Jeu.

Chargement des options au début de la procédure RunGame du module clGame
Sélectionnez
' Chargement des options
oSharedData.NbFantomes = ReadOption("NbFantomes", 5)
oSharedData.ToucheBas = ReadOption("ToucheBas", vbKeyDown)
oSharedData.ToucheDroite = ReadOption("ToucheDroite", vbKeyRight)
oSharedData.ToucheGauche = ReadOption("ToucheGauche", vbKeyLeft)
oSharedData.ToucheHaut = ReadOption("ToucheHaut", vbKeyUp)
oSharedData.ToucheValid = ReadOption("ToucheValid", vbKeyReturn)
oSharedData.JoyNum = ReadOption("JoyNum", 0)
oSharedData.JoyButton = ReadOption("JoyButton", 0)

Les options sont lues dans le fichier config.ini grâce à la fonction ReadOption écrite précédemment.
On passe en paramètre une valeur par défaut pour le cas où l'option n'est pas définie dans le fichier de configuration.

Pour le joypad, une fois lu le joypad choisi dans les options, on affecte ce joypad à l'objet command.

Affectation du jopypad
Sélectionnez
' Affecte le joystick à l'objet command
oCommand.JoyPadNum = oSharedData.JoyNum

XIII-D. Création de l'écran des options de jeu

Cet écran se programme dans le module clScreenOption.

Préparons l'écran en copiant dans ce module le contenu du module clScreenMenu de l'écran de menu.

Nettoyez le module en retirant la fonction DisplayOption qui ne nous servira pas pour cet écran, ainsi que tous les appels à cette fonction.

Il faut ensuite gérer l'enchaînement de l'écran des options.

Dans la fonction GameChangeScreen du module clGame, il faut ajouter l'enchainement vers l'écran des options.

Ajoutez un Case au Select.

Enchainement vers écran d'options dans clGame
Sélectionnez
' Changement pour les options
        Case "options"
            Set oScreen = Nothing
            Set oScreen = New clScreenOptions

On teste la valeur « options » car dans l'écran de menu c'est cette valeur qu'on utilise lors du click sur Options.

Puis modifier le texte de l'écran d'options pour pouvoir tester, en remplaçant la ligne qui écrivait « Pacman en VBA ».

Texte en haut de l'écran clScreenOptions
Sélectionnez
' 0 - Ecrit le titre de l'écran en haut
    .DrawText "Options de jeu", 35, "Arial", 0, 10, .ImageWidth, _
            10 + 50, 1, 0, vbBlue, , vbYellow

Cliquez dans le menu sur « OPTIONS » affiche bien l'écran des options.

XIII-E. Affichage des options de jeu

Faisons une petite maquette (sous PowerPoint par exemple) pour se donner une idée de l'écran d'options que l'on doit réaliser.

Image non disponible

Chaque cadre sera encadré lorsque sélectionné.

Après l'écriture du texte « Options de jeu », on écrit le code qui dessine la partie statique de l'écran d'options.

Code de dessin à placer après l'écriture du titre et avant le ImageKeep
Sélectionnez
' 1 - Affichage du nombre de fantômes
    .DrawText "Nombre de fantômes", 20, , 120, 100, 400, 130, 0, , vbBlue
    .DrawRectangle 310, 100, 370, 130, , vbWhite, 2, , , "NbFantomes"
    ' 2 - Affichage commandes clavier
    .DrawText "Commandes clavier", 20, , 120, 140, 400, 170, 0, , vbBlue
    .DrawRectangle 120, 170, 600, 410, , vbBlack, 1
    .DrawRectangle 310, 180, 400, 210, , vbWhite, 2, , , "ToucheHaut"
    .DrawText "Haut", 20, , 310, 180, 400, 210, , , vbBlue
    .DrawRectangle 310, 280, 400, 310, , vbWhite, 2, , , "ToucheBas"
    .DrawText "Bas", 20, , 310, 280, 400, 310, , , vbBlue
    .DrawRectangle 310, 350, 400, 380, , vbWhite, 2, , , "ToucheValid"
    .DrawText "Valider", 20, , 310, 350, 400, 380, , , vbBlue
    .DrawRectangle 160, 230, 250, 260, , vbWhite, 2, , , "ToucheGauche"
    .DrawText "Gauche", 20, , 160, 230, 250, 260, , , vbBlue
    .DrawRectangle 460, 230, 550, 260, , vbWhite, 2, , , "ToucheDroite"
    .DrawText "Droite", 20, , 460, 230, 550, 260, , , vbBlue
    ' 2 - Affichage commandes joystick
    .DrawText "Commandes joystick", 20, , 120, 420, 400, 450, 0, , vbBlue
    .DrawRectangle 120, 450, 600, 510, , vbBlack, 1
    .DrawRectangle 200, 460, 500, 490, , vbWhite, 2, , , "JoyButton"
    .DrawText "Bouton de validation", 20, , 200, 460, 500, 490, , , vbBlue
    ' 4 - Affichage des boutons valider et annuler
    .DrawRectangle 180, 530, 310, 560, RGB(150, 255, 150), vbBlack, 1, , , "BoutonValid"
    .DrawText "Valider", 20, , 180, 530, 310, 560, , , vbBlue
    .DrawRectangle 400, 530, 550, 560, RGB(255, 150, 150), vbBlack, 1, , , "BoutonCancel"
    .DrawText "Annuler", 20, , 400, 530, 550, 560, , , vbBlue

Comme pour le menu, on ajoute des régions rectangulaires à l'appel des fonctions DrawRectangle.

Lancez le formulaire et cliquez sur le menu « OPTIONS » pour tester.

Image non disponible

On s'aperçoit que le code utilisé pour encadrer les options de menu fonctionne toujours dans cet écran.
Par contre on va modifier l'option choisie par défaut :

Option choisie par défaut dans Class_Initialize
Sélectionnez
' Option sélectionnée par défaut
gOption = "BoutonCancel"

Ainsi le bouton « Annuler » est sélectionné par défaut.

Une fois tous les cadres dessinés, on va écrire les valeurs des options :

  • on écrit le nombre de fantôme dans la région (=le rectangle) ;
  • et on écrit le nom de chaque touche et bouton sous la région (=le rectangle).

Ecrivons deux petites procédures pour écrire ces données :

Procédure pour écrire sous une région
Sélectionnez
'------------------------------------------------------------------------
' Affichage texte sous une région
'------------------------------------------------------------------------
Private Function DisplayTextUnderRegion(pRegion As String, pText As String)
    Dim lX1 As Long, lY1 As Long, lX2 As Long, lY2 As Long
    ' Position de la région pRegion
    If oGdi.RegionGetRect(pRegion, lX1, lY1, lX2, lY2) Then
        ' Ecrit le texte en noir et italique
        oGdi.DrawText pText, 15, , (lX2 + lX1) / 2, lY2 + 10, , , , , vbBlack, , , , True
    End If
End Function
Procédure pour écrire dans une région
Sélectionnez
'------------------------------------------------------------------------
' Affichage texte sur une région
'------------------------------------------------------------------------
Private Function DisplayTextInRegion(pRegion As String, pText As String)
    Dim lX1 As Long, lY1 As Long, lX2 As Long, lY2 As Long
    ' Position de la région pRegion
    If oGdi.RegionGetRect(pRegion, lX1, lY1, lX2, lY2) Then
        '  Ecrit le texte en noir
        oGdi.DrawText pText, 20, , lX1, lY1, lX2, lY2, , , vbBlack
    End If
End Function

Nous utiliserons ces procédures pour afficher les valeurs des options dans la procédure de mise à jour ClScreen_UpdateScreen.

Les différentes valeurs sont stockées dans l'objet oSharedData.

Pour les touches, la valeur de l'option est le code numérique de la touche.
On va créer une petite fonction pour récupérer le nom de la touche en toute lettre.
Plaçons cette procédure dans le module ModFunctions.

Déclarations en haut de module
Sélectionnez
' Déclaration pour nom des touches
#If VBA7 Then
Private Declare PtrSafe Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" _
                        (ByVal wCode As Long, ByVal wMapType As Long) As Long
Private Declare PtrSafe Function GetKeyNameText Lib "user32" Alias "GetKeyNameTextA" _
                        (ByVal lParam As Long, ByVal lpBuffer As String, ByVal nSize As Long) As Long
#Else
Private Declare Function MapVirtualKey Lib "user32" Alias "MapVirtualKeyA" _
                        (ByVal wCode As Long, ByVal wMapType As Long) As Long
Private Declare Function GetKeyNameText Lib "user32" Alias "GetKeyNameTextA" _
                        (ByVal lParam As Long, ByVal lpBuffer As String, ByVal nSize As Long) As Long
#End If
Fonction qui renvoit le texte d'une touche à partir de son code
Sélectionnez
'------------------------------------------------------------------------
' Renvoit le texte d'une touche à partir de son code
'------------------------------------------------------------------------
Public Function KeyNameFromKeyCode(pKeyCode As Long) As String
Dim lKeyCode As Long
Dim lBuffer As String
Dim lSize As Long
            
lKeyCode = MapVirtualKey(pKeyCode, 0)
lKeyCode = lKeyCode * &H10000
lBuffer = Space$(256)
lSize = GetKeyNameText(lKeyCode, lBuffer, 256)
KeyNameFromKeyCode = Left$(lBuffer, lSize)
End Function

Retour au module clScreenOptions.
Après l'encadrement de région, dans la procédure ClScreen_UpdateScreen, on ajoute le dessin des valeurs des options.

Dessin des valeurs des options
Sélectionnez
' Ecrit le nombre de fantômes
    DisplayTextInRegion "NbFantomes", CStr(oSharedData.NbFantomes)
    ' Ecrit le texte des touches
    DisplayTextUnderRegion "ToucheBas", "( " & KeyNameFromKeyCode(oSharedData.ToucheBas) & " )"
    DisplayTextUnderRegion "ToucheHaut", "( " & KeyNameFromKeyCode(oSharedData.ToucheHaut) & " )"
    DisplayTextUnderRegion "ToucheDroite", "( " & KeyNameFromKeyCode(oSharedData.ToucheDroite) & " )"
    DisplayTextUnderRegion "ToucheGauche", "( " & KeyNameFromKeyCode(oSharedData.ToucheGauche) & " )"
    DisplayTextUnderRegion "ToucheValid", "( " & KeyNameFromKeyCode(oSharedData.ToucheValid) & " )"
    ' Ecrit le texte pour le bouton de joystick
    DisplayTextUnderRegion "JoyButton", _
            "( Bouton " & oSharedData.JoyButton & " du joystick " & oCommand.JoyPadName & " )"

Lancez le formulaire et cliquez sur le menu « OPTIONS » pour tester l'affichage des valeurs.

Image non disponible

XIII-F. Modification des options de jeu

Pour modifier une option, l'utilisateur devra survoler l'option à la souris puis appuyer sur la touche souhaitée.

Pour connaître la touche appuyée, on utilisera la fonction KeyPressGetCode de l'objet oCommand.
Cette fonction revoit le code numérique d'une seule touche appuyée (même si on appuie sur plusieurs touches simultanément).

Si une touche est appuyée et qu'une option est survolée, alors on modifie la valeur de l'option.

Pour le joystick, on teste l'état de tous les boutons de tous les joysticks présents.
Si un bouton est appuyé, il devient le bouton de validation.

La détection de touche ou joystick se fait dans la fonction ClScreen_UpdateCommand.

Modification des options sur appuis de touche ou joystick dans ClScreen_UpdateCommand
Sélectionnez
Dim lKeyPress As Long
Dim loCommand As ClCommand
Dim lCpt As Long
' Code de la touche appuyée
lKeyPress = oCommand.KeyPressGetCode
' Si une touche est appuyée
If lKeyPress <> 0 Then
    Select Case gOption
        Case "ToucheHaut"
            oSharedData.ToucheHaut = lKeyPress
        Case "ToucheBas"
            oSharedData.ToucheBas = lKeyPress
        Case "ToucheDroite"
            oSharedData.ToucheDroite = lKeyPress
        Case "ToucheGauche"
            oSharedData.ToucheGauche = lKeyPress
        Case "ToucheValid"
            oSharedData.ToucheValid = lKeyPress
        Case "NbFantomes"
            If IsNumeric(Chr(lKeyPress)) Then
                ' Touche numérique
                oSharedData.NbFantomes = Val(Chr(lKeyPress))
            ElseIf Val(KeyNameFromKeyCode(lKeyPress)) <> 0 Then
                ' Touche du pavé numérique
                oSharedData.NbFantomes = Val(KeyNameFromKeyCode(lKeyPress))
            End If
    End Select
End If
' Teste des touches de joystick
' Objet command local pour test de tous les joysticks
Set loCommand = New ClCommand
' Premier joystick, commence à l'indice 0
loCommand.JoyPadNum = 0
Do
    ' Si pas de bouton => joystick invalide => sort de la boucle
    If loCommand.JoyPadButtons = 0 Then Exit Do
    ' Teste l'état de tous les boutons
    For lCpt = 0 To loCommand.JoyPadButtons
        ' Teste l'appui sur le bouton n° lCpt
        If loCommand.TestJoypadButton(lCpt) Then
            ' Modifie les options en fonction du bouton et du joystick utilisé
            oSharedData.JoyButton = lCpt
            oSharedData.JoyNum = loCommand.JoyPadNum
            ' Affecte le joystick choisi à l'objet command global
            oCommand.JoyPadNum = loCommand.JoyPadNum
            ' Sort de la boucle
            Exit Do
        End If
    Next
    ' Joystick suivant
    loCommand.JoyPadNum = loCommand.JoyPadNum + 1
Loop

Pour le nombre de fantôme, on vérifie si la touche appuyée correspond à une touche de chiffre (en haut sur le clavier), ou à une touche du pavé numérique.

XIII-G. Validation ou annulation des options de jeu

Il faut maintenant gérer la validation ou l'annulation des options.

Sur click sur le bouton « Valider » ou le bouton « Annuler », on retourne au menu.
Modifions donc l'écran suivant par défaut de cet écran d'options.

Retour par défaut au menu dans Class_Initialize
Sélectionnez
' Ecran suivant par défaut
gNextScreen = "menu"

Ensuite modifions la procédure MenuSelect de notre écran.

Sélection de valider ou annuler
Sélectionnez
'------------------------------------------------------------------------
' Sélection dans le menu
'------------------------------------------------------------------------
Private Sub MenuSelect()
Select Case gOption
    Case "BoutonValid"
        gChangeScreen = True
    Case "BoutonCancel"
        gChangeScreen = True
End Select
End Sub

Inutile de préciser l'écran suivant, c'est l'écran par défaut dans les deux cas.

Pour compléter :
Sur click sur le bouton annuler on va recharger les options pour annuler les changements.
Par contre sur click sur le bouton valider, on va sauvegarder les options.

Code complet : Sélection de valider ou annuler
Sélectionnez
'------------------------------------------------------------------------
' Sélection dans le menu
'------------------------------------------------------------------------
Private Sub MenuSelect()
Select Case gOption
    Case "BoutonValid"
        ' Sauvegarde des options
        WriteOption "NbFantomes", oSharedData.NbFantomes
        WriteOption "ToucheBas", oSharedData.ToucheBas
        WriteOption "ToucheDroite", oSharedData.ToucheDroite
        WriteOption "ToucheGauche", oSharedData.ToucheGauche
        WriteOption "ToucheHaut", oSharedData.ToucheHaut
        WriteOption "ToucheValid", oSharedData.ToucheValid
        WriteOption "JoyNum", oSharedData.JoyNum
        WriteOption "JoyButton", oSharedData.JoyButton
        ' Demande le changement d'écran
        gChangeScreen = True
    Case "BoutonCancel"
        ' Rechargement des options
        oSharedData.NbFantomes = ReadOption("NbFantomes", 5)
        oSharedData.ToucheBas = ReadOption("ToucheBas", vbKeyDown)
        oSharedData.ToucheDroite = ReadOption("ToucheDroite", vbKeyRight)
        oSharedData.ToucheGauche = ReadOption("ToucheGauche", vbKeyLeft)
        oSharedData.ToucheHaut = ReadOption("ToucheHaut", vbKeyUp)
        oSharedData.ToucheValid = ReadOption("ToucheValid", vbKeyReturn)
        oSharedData.JoyNum = ReadOption("JoyNum", 0)
        oSharedData.JoyButton = ReadOption("JoyButton", 0)
        ' Affecte le joystick à l'objet command
        oCommand.JoyPadNum = oSharedData.JoyNum
        ' Demande le changement d'écran
        gChangeScreen = True
End Select
End Sub

Affichez l'écran d'options et validez : le fichier congfig.ini a été créé dans le sous-dossier config.

Une dernière chose avant de clore ce chapitre.
Si on utilise le joystick, une fois entré dans l'écran d'options on ne peut en sortir qu'avec la souris.
Cela n'est pas très pratique, on va donc tester si on appuie sur le bouton de joystick de validation afin de pouvoir quitter l'écran au joystick.

Dans clScreenOptions, au début de la fonction ClScreen_UpdateCommand
Sélectionnez
' Si appui sur la touche de validation du joystick
If oCommand.TestJoypadButton(oSharedData.JoyButton) Then
    ' Valide le menu sélectionné (annuler par défaut)
    MenuSelect
    Exit Function
End If

Voilà qui est plus pratique.

XIII-H. Navigation dans l'écran de menu avec le clavier ou le joystick

Maintenant que nous avons toutes nos commandes définies, nous pouvons également les utiliser pour naviguer dans l'écran de menu.

Ouvrez le module clScreenMenu et ajouter la navigation au clavier et joystick dans la procédure ClScreen_UpdateCommand.

Dans UpdateCommand du module clScreenMenu
Sélectionnez
Dim lCpt As Long
Dim lDown As Boolean
Dim lUp As Boolean
' Test directions du joystick
oCommand.TestJoypadDir , , lUp, lDown
' Numéro du menu sélectionné
lCpt = Right(gOption, 1)
' Si appuis touche vers le bas
If oCommand.TestKey(oSharedData.ToucheBas, 100) Or lDown Then
    lCpt = lCpt + 1
    If lCpt = 6 Then lCpt = 1
    gOption = "menu" & lCpt
End If
' Si appuis touche vers le haut
If oCommand.TestKey(oSharedData.ToucheHaut, 100) Or lUp Then
    lCpt = lCpt - 1
    If lCpt = 0 Then lCpt = 5
    gOption = "menu" & lCpt
End If
' Test si validation
If oCommand.TestKey(oSharedData.ToucheValid, 100) Or oCommand.TestJoypadButton(oSharedData.JoyButton, 100) Then
    MenuSelect
End If

On peut ainsi naviguer dans menu et valider soit à la souris, au clavier, ou au joystick.


précédentsommairesuivant

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2013 Thierry GASPERMENT. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts. Droits de diffusion permanents accordés à Developpez LLC.