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

XVI. Développement de l'écran de jeu perdu

Préparez le module clScreenGameOver de la même manière que le module clScreenMenu au chapitre Préparation du premier écran : le menu clScreenMenu.

Pensez à gérer l'affichage et la minuterie (10 images par seconde suffisent).

Affichage et minuterie dans clScreenGameOver
Sélectionnez
'------------------------------------------------------------------------
' Affichage de l'écran
'------------------------------------------------------------------------
Private Function ClScreen_DisplayScreen() As Boolean
' Dessine l'image sur le formulaire
oGdi.RepaintNoFormRepaint FormGame.Img
End Function
            
'------------------------------------------------------------------------
' Minuterie d'attente
'------------------------------------------------------------------------
Private Function ClScreen_ScreenWait() As Boolean
' Attente de 1000 / 10 = 100 ms pour affichage de 10 images/s
oGdi.Wait 100
End Function

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

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

Ajoutez un Case au Select.

Enchainement vers écran de jeu perdu dans clGame
Sélectionnez
' Changement pour le jeu perdu
        Case "gameover"
            Set oScreen = Nothing
            Set oScreen = New ClScreenGameOver

On teste la valeur « gameover » car dans l'écran de jeu c'est cette valeur qu'on utilise lorsque le PacMan est mangé.

A l'initialisation de l'écran, on défini l'écran des scores en écran suivant par défaut.

Ecran par défaut dans clGameOver
Sélectionnez
' Ecran suivant par défaut
gNextScreen = "scores"

A l'initialisation de l'écran, on écrit le texte de fin de jeu.

Dessin du contenu statique dans Class_Initialize
Sélectionnez
' Dessin du contenu statique
With oGdi
    ' Nouveau bitmap pour dessiner
    .CreateBitmap .PointsToPixelsX(FormGame.Img.Width), .PointsToPixelsY(FormGame.Img.Height)
    ' Rempli l'image de gris
    .FillColor RGB(150, 150, 150)
    ' Ecrit le texte jeu perdu en haut
    .DrawText "JEU PERDU", 35, "Arial", 0, 20, .ImageWidth, 60, , , _
                                                vbBlue, , vbYellow 
    ' Sauvegarde l'image en mémoire
    .ImageKeep
End With

A la mise à jour de l'écran, on écrit le score.
(On n'écrit pas le score à l'initialisation car on n'y a pas accès à l'objet oSharedData)

Affichage du score dans ClScreen_UpdateScreen
Sélectionnez
With oGdi
    ' Reprend l'image de la mémoire
    .ImageReset
    ' Ecrit le score du joueur
    .DrawText "SCORE : " & oSharedData.Score, 35, "Arial", 20, 80, .ImageWidth, 120, , 0, _
                                                vbBlue, , vbYellow 
End With

Il faut ensuite vérifier si on entre dans les meilleurs scores.
Pour l'instant les scores ne sont pas gérés.
On va créer dans le sous-dossier config un fichier scores.ini qui contiendra les 10 meilleurs scores.

fichier scores.ini avec scores initiaux
Sélectionnez
[1]
name=initial
score=10
[2]
name=initial
score=10
[3]
name=initial
score=10
[4]
name=initial
score=10
[5]
name=initial
score=10
[6]
name=initial
score=10
[7]
name=initial
score=10
[8]
name=initial
score=10
[9]
name=initial
score=10
[10]
name=initial
score=10

Pour chaque score il y a deux valeurs : le nom et le score.

Comme nous l'avions fait pour les options, nous allons créer des fonctions de gestion du fichier scores.ini.

Fonctions de gestion des scores dans le module ModFunctions
Sélectionnez
'------------------------------------------------------------------------
' Lecture de la valeur du score numéro pNum
' pKey = name ou score
'------------------------------------------------------------------------
Public Function ReadScore(pNum As Long, pKey As String) As String
Dim lRet As Long
Dim lData As String
Dim lSize As Long
lData = Space$(8192)
lSize = 8192
lRet = GetPrivateProfileString(CStr(pNum), pKey, "", lData, lSize, ThisWorkbook.path & "\config\scores.ini")
If lSize > 0 Then
    ReadScore = Left$(lData, lRet)
Else
    ReadScore = ""
End If
End Function
            
'------------------------------------------------------------------------
' Ecriture de la valeur du score numéro pNum
'------------------------------------------------------------------------
Public Function WriteScore(pNum As Long, pName As String, pScore As Long) As Boolean
Dim lRet As Long
Dim lSize As Long
lRet = WritePrivateProfileString(pNum, "name", pName, ThisWorkbook.path & "\config\scores.ini")
lRet = WritePrivateProfileString(pNum, "score", CStr(pScore), ThisWorkbook.path & "\config\scores.ini")
WriteScore = (lRet <> 0)
End Function
            
'---------------------------------------------------------------------------------------
' Vérifie si on entre dans les scores
'---------------------------------------------------------------------------------------
Public Function GetPosHiScore(pScore As Long) As Long
Dim lCpt As Long
' Recherche la ligne où insérer le score si assez élevé
For lCpt = 1 To 10
    If pScore > ReadScore(CStr(lCpt), "score") Then
        GetPosHiScore = lCpt
        Exit For
    End If
Next
End Function
            
'---------------------------------------------------------------------------------------
' Mise à jour des HighScore
'---------------------------------------------------------------------------------------
Public Sub UpdateHiScore(pPosition As Long, pName As String, pScore As Long)
Dim lCpt As Long
' Si entrée dans les scores
' Décale les scores vers le bas
For lCpt = 10 To pPosition + 1 Step -1
    WriteScore CStr(lCpt), ReadScore(CStr(lCpt - 1), "name"), ReadScore(CStr(lCpt - 1), "score")
Next
' Ajoute les infos du nouveau score
WriteScore CStr(pPosition), pName, CStr(pScore)
End Sub
  • ReadScore lit le nom ou le score numéro pNum.
  • WriteScore écrit un score en position pNum.
  • GetPosHiScore renvoit la position du score pScore dans les meilleurs scores.
  • UpdateHiScore insère un nouveau score en position pNum.

Retour au module clScreenGameOver dans lequel nous avons besoin de déclarer deux nouvelles variables.

Variables en en-tête de clScreenGame
Sélectionnez
' Position dans les scores
Private gPosHiScore As Long
' Nom pour entrée dans les scores
Private gName As String

A l'ouverture de l'écran, on défini la valeur de gPosHiScore à -1 (la valeur de -1 nous indique qu'on doit déterminer la position, on ne le fera qu'une seule fois).

Dans Class_Initialize, initialise la valeur de gPosHiScore
Sélectionnez
' Position dans les scores à déterminer
gPosHiScore = -1

Ensuite dans la mise à jour de l'écran, on détermine la position dans les meilleurs scores.

Puis, toujours dans la mise à jour de l'écran, on écrit si nécessaire le texte indiquant au joueur qu'il doit entrer son nom.

Dans ClScreen_UpdateScreen, affiche le texte d'entrée de nom pour les scores
Sélectionnez
Static sClignote As Long
' Position dans les scores
If gPosHiScore = -1 Then gPosHiScore = GetPosHiScore(oSharedData.Score)
With oGdi
    ' Reprend l'image de la mémoire
    .ImageReset
    ' Ecrit le score du joueur
    .DrawText "SCORE : " & oSharedData.Score, 35, "Arial", 0, 80, .ImageWidth, 120, , 0, _
                                                vbBlue, , vbYellow
    ' Edition du nom pour entrée dans les scores
    If gPosHiScore > 0 Then
        oGdi.DrawText "Entrée dans les meilleurs scores", 25, "Arial", _
                    20, 140, .ImageWidth, 180, 0, , vbRed
        oGdi.DrawText "Nom du joueur : " & gName & IIf(sClignote < 5, "_", " "), 25, "Arial", _
                    20, 200, .ImageWidth, 240, 0, , vbBlack
    End If
    sClignote = (sClignote + 1) Mod 10
End With
Image non disponible

On utilise une variable statique (qui n'est pas remise à zéro à chaque exécution de la fonction) pour faire clignoter un curseur.
Le curseur est un caractère de soulignement affiché la moitié du temps.

Pour terminer, on va modifier la gestion des commandes ClScreen_UpdateCommand.
Les touches acceptées pour l'entrée du nom du joueur sont les touches de lettres (A à Z) et de chiffres (0 à 9).
La touche de retour arrière supprime le dernier caractère.

Dans ClScreen_UpdateCommand, modifie le nom du joueur en fonction des touches appuyées
Sélectionnez
Dim lKey As Long
' Définition du nom pour les meilleurs scores
If gPosHiScore > 0 Then
    ' Touche appuyée
    lKey = oCommand.KeyPressGetCode
    ' Test si touche = lettre ou chiffre
    If (lKey >= vbKeyA And lKey <= vbKeyZ) Or (lKey >= vbKey0 And lKey <= vbKey9) Then
        ' Ajoute le caractère au nom
        gName = gName & Chr(lKey)
    End If
    ' Test si touche de retour arrière => suppression du dernier caractère
    If lKey = vbKeyBack Then
        If Len(gName) > 0 Then gName = Left(gName, Len(gName) - 1)
    End If
End If

Enfin on bascule vers l'écran suivant sur validation (souris, clavier, ou joystick).
Si le joueur est entré dans les scores, on insère son score dans le fichier ini.

Bascule vers l'écran suivant et insertion du score sur validation dans ClScreen_UpdateCommand
Sélectionnez
' Test si validation
If oCommand.TestKey(oSharedData.ToucheValid, 500) Or _
        oCommand.TestJoypadButton(oSharedData.JoyButton, 500) Then
    ' Si meilleur score à sauvegarder
    If gPosHiScore > 0 Then
        Call UpdateHiScore(gPosHiScore, gName, oSharedData.Score)
    End If
    ' Demande le changement d'écran
    gChangeScreen = True
End If

Mangez au moins 10 pastilles et allez à la rencontre d'un fantôme pour tester la mise à jour des scores.

XVII. Développement de l'écran de jeu gagné

Pour l'écran de jeu gagné, on va faire simple.
On copie-colle dans clScreenGameEnd le contenu du module clScreenGameOver.
Ensuite on modifie juste le texte du contenu statique :

Modification du texte
Sélectionnez
' Ecrit le texte jeu gagné en haut
    .DrawText "JEU GAGNE", 35, "Arial", 0, 20, .ImageWidth, 60, , , _
                                                vbBlue, , vbYellow

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

Dans la fonction GameChangeScreen du module clGame, il faut ajouter l'enchainement vers l'écran de jeu gagné.

Ajoutez un Case au Select.

Enchainement vers écran de jeu gagné dans clGame
Sélectionnez
' Changement pour le jeu gagné
        Case "gameend"
            Set oScreen = Nothing
            Set oScreen = New ClScreenGameEnd

XVIII. Développement de l'écran des scores

On ne va pas trop détailler la création de cet écran, la méthode est la même que pour les autres écrans.
L'écran suivant par défaut est l'écran des crédits :

Ecran suivant : écran des crédits par défaut
Sélectionnez
' Ecran suivant par défaut
gNextScreen = "credits"

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

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

Ajoutez un Case au Select.
Cet enchaînement est un peu particulier car si on affiche les scores à partir du menu, on souhaite revenir au menu.
On teste donc le type d'écran en cours avant de basculer vers l'écran suivant, puis on change le nom de l'écran suivant pour retourner au menu le cas échéant.

Enchainement vers écran des scores dans clGame
Sélectionnez
' Variable pour écran suivant
Dim lNextScreen As String
[...]
        ' Changement pour les scores
        Case "scores"
            If TypeOf oScreen Is ClScreenMenu Then
                lNextScreen = "menu"
            End If
            Set oScreen = Nothing
            Set oScreen = New clScreenScores
            If lNextScreen <> "" Then oScreen.NextScreen = lNextScreen

On pense à changer d'écran sur validation.

Bascule vers l'écran suivant si validation dans clScreenScores
Sélectionnez
' Test si validation
If oCommand.TestKey(oSharedData.ToucheValid, 500) Or _
        oCommand.TestJoypadButton(oSharedData.JoyButton, 500) Then
    ' Demande le changement d'écran
    gChangeScreen = True
End If

Petite différence pour cet écran : il est statique.
Donc il n'est pas nécessaire de mettre à jour l'écran à chaque itération de la minuterie.
On laisse donc vide les fonctions ClScreen_UpdateScreen et ClScreen_DisplayScreen.
Le contenu de l'écran sera dessiné et affiché à l'initialisation dans Class_Initialize.

Ecriture des scores dans Class_Initialize de clScreenScores
Sélectionnez
Set oGdi = New clGdiplus ' Objet pour graphiques
Set oSound = New clSound ' Objet pour sons
Dim lX1 As Long, lY1 As Long ' Variables pour positionnement des textes
Dim lCpt As Long ' Compteur pour scores
' Ecran suivant par défaut
gNextScreen = "credits"
' Dessin du contenu statique
With oGdi
    ' Nouveau bitmap pour dessiner
    .CreateBitmapForControl FormGame.img
    ' Rempli l'image de gris
    .FillColor RGB(150, 150, 150)
    ' Ecrit le texte jeu gagné en haut
    ' Affiche les scores
    .DrawText "Meilleurs scores", 40, , 2, 120 + 2, .ImageWidth + 2, 160 + 2, , , vbBlack, 150, , , , True
    .DrawText "Meilleurs scores", 40, , 0, 120, .ImageWidth, 160, , , vbRed, , , , , True
    .DrawLine 50, 165, .ImageWidth - 50, 165, vbBlack, 3, True, 150
    lY1 = 175
    lX1 = 50
    For lCpt = 1 To 10
        .DrawText ReadScore(CStr(lCpt), "name"), 30, , .ImageWidth / 2, lY1, , , 0, 2, vbBlue
        .DrawText ReadScore(CStr(lCpt), "score"), 30, , .ImageWidth / 2 + 10, lY1, , , 2, 2, vbRed
        lY1 = lY1 + 30
    Next
    ' Dessine l'image sur le formulaire
    oGdi.RepaintNoFormRepaint FormGame.img
End With

Testez l'affichage des scores en cliquant sur SCORE dans le menu.

Image non disponible

XIX. Développement de l'écran des crédits

On crée l'écran comme on l'a fait pour tous les autres.

code de base de l'écran clScreenCredits
Sélectionnez
'***************************************************************************************
'*                             OBJET ECRAN DES CREDITS
'***************************************************************************************
Option Explicit
            
' Implémente l'interface de base des écrans
Implements ClScreen
' Objet pour commandes
Private oCommand As ClCommand
' Objet pour données partagées
Private oSharedData As ClSharedData
' Objet pour sons
Private oSound As ClSound
' Objet pour gdiplus
Private oGdi As ClGdiplus
' Indicateur pour changement d'écran
Private gChangeScreen As Boolean
' Nom de l'écran suivant
Private gNextScreen As String
            
'------------------------------------------------------------------------
' Initialisation de l'objet
' =>création des objets nécessaire à l'écran
'------------------------------------------------------------------------
Private Sub Class_Initialize()
Set oGdi = New ClGdiplus ' Objet pour graphiques
Set oSound = New ClSound ' Objet pour sons
' Ecran suivant par défaut
gNextScreen = "menu"
' Dessin du contenu statique
With oGdi
    ' Nouveau bitmap pour dessiner
    .CreateBitmap .PointsToPixelsX(FormGame.Img.Width), .PointsToPixelsY(FormGame.Img.Height)
    ' Rempli l'image de gris
    .FillColor RGB(150, 150, 150)
    ' Sauvegarde l'image en mémoire
    .ImageKeep
End With
End Sub
            
'------------------------------------------------------------------------
' Implémentation des propriétés de l'interface
'------------------------------------------------------------------------
Private Property Get ClScreen_ChangeScreen() As Boolean
ClScreen_ChangeScreen = gChangeScreen
End Property
            
Private Property Set ClScreen_Command(RHS As ClCommand)
Set oCommand = RHS
End Property
            
Private Property Let ClScreen_NextScreen(RHS As String)
gNextScreen = RHS
End Property
            
Private Property Get ClScreen_NextScreen() As String
ClScreen_NextScreen = gNextScreen
End Property
            
Private Property Set ClScreen_SharedData(RHS As ClSharedData)
Set oSharedData = RHS
End Property
            
'------------------------------------------------------------------------
' Mise à jour des commandes
'------------------------------------------------------------------------
Private Function ClScreen_UpdateCommand() As Boolean
' Test si validation
If oCommand.TestKey(oSharedData.ToucheValid, 500) Or _
        oCommand.TestJoypadButton(oSharedData.JoyButton, 500) Then
    ' Demande le changement d'écran
    gChangeScreen = True
End If
End Function
            
'------------------------------------------------------------------------
' Mise à jour de l'écran
'------------------------------------------------------------------------
Private Function ClScreen_UpdateScreen() As Boolean
With oGdi
    ' Reprend l'image de la mémoire
    .ImageReset
End With
End Function
            
'------------------------------------------------------------------------
' Affichage de l'écran
'------------------------------------------------------------------------
Private Function ClScreen_DisplayScreen() As Boolean
' Dessine l'image sur le formulaire
oGdi.RepaintNoFormRepaint FormGame.Img
End Function
            
'------------------------------------------------------------------------
' Minuterie d'attente
'------------------------------------------------------------------------
Private Function ClScreen_ScreenWait() As Boolean
' Attente de 1000 / 40 = 25 ms pour affichage de 40 images/s
oGdi.Wait 25
End Function

L'écran suivant après les crédits est le menu.
On met à jour l'affichage 40 fois par secondes car on va afficher un texte déroulant.

Pour gérer un scrolling, on va d'abord dessiner le texte des crédits sur une image plus grande que l'image du jeu.
Ensuite on va dessiner cette image sur l'image principale à chaque itération de la minuterie.
En décalant l'image d'un pixel à chaque affichage, on obtiendra un défilement.
Pour que le texte s'enroule sans fin, on utilisera le paramètre gWrapY de l'objet oGdi.

Ecriture des crédits dans Class_Initialize
Sélectionnez
' Dessin du contenu statique
With oGdi
[...]
    ' Nouvelle image pour les crédits (2 fois plus haute que l'image principale
    With .ImgNew("credits", .ImageWidth, .ImageHeight * 2)
        .DrawText "Tutoriel jeu en VBA", 40, , 0, 40, .ImageWidth, 90, , , vbYellow
        .DrawText "Ecrit pour developpez.com", 30, , 0, 120, .ImageWidth, 160, , , vbYellow
        .DrawText "Dessins des sprites avec Microsoft ® Paint", 30, , 0, 170, .ImageWidth, 210, , , vbYellow
        .DrawText "Sons enregistrés avec le magnétophone Windows", 30, , 0, 220, .ImageWidth, 260, , , vbYellow
        .DrawText "Auteur : arkham46", 30, , 0, 270, .ImageWidth, 310, , , vbYellow
        .DrawText "Site Web : arkham46.developpez.com", 30, , 0, 320, .ImageWidth, 360, , , vbBlue
    End With
End With
Défilement des crédits dans ClScreen_UpdateScreen
Sélectionnez
' Variable pour décalage
Static gDecalage As Long
With oGdi
    ' Reprend l'image de la mémoire
    .ImageReset
    ' Décalage de 1 pixels
    gDecalage = gDecalage + 1
    ' Affecte le décalage
    .WrapY = gDecalage
    ' On dessine l'image des crédits
    .DrawImg "credits", 0, 0, .ImageWidth, .ImageHeight, , GdipSizeModeClip, GdipAlignBottomLeft
    ' On annule ensuite le décalage
    .WrapY = 0
End With

L'image des crédits est dessinée avec un mode GdipSizeModeClip pour ne pas redimensionner l'image.
Elle est alignée en bas (GdipAlignBottomLeft) pour débuter un affichage qui commence en bas et qui remonte.

Puis dans la fonction GameChangeScreen du module clGame, il faut ajouter l'enchainement vers l'écran de crédits.

Ajoutez un Case au Select.

Enchainement vers écran de jeu gagné dans clGame
Sélectionnez
        ' Changement pour les crédits
        Case "credits"
            Set oScreen = Nothing
            Set oScreen = New clScreenCredits

Testez l'affichage des crédits en cliquant sur CREDITS dans le menu.

Image non disponible

XX. Lancement du jeu à l'ouverture d'Excel

Une toute dernière chose avant de nous quitter.
Il serait intéressant que le jeu se lance à l'ouverture du fichier Excel.
Pour cela on va afficher le formulaire au chargement du classeur.

Dans l'explorateur de projet à gauche, repérez le module ThisWorkbook.
Double-cliquez dessus et sélectionnez WorkBookdans les listes déroulantes en haut.
La procédure Workbook_Open est créée, on y insère le code d'affichage du formulaire.

Affichage du formulaire à l'ouverture du classeur
Sélectionnez
'---------------------------------------------------------------------------------------
' Procédure exécutée à l'ouverture du classeur Excel
'---------------------------------------------------------------------------------------
Private Sub Workbook_Open()
' Affiche le formulaire de jeu
FormGame.Show
End Sub

Fermez et rouvrez le classeur pour tester.


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.