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 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.
' 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 suivant par défaut
gNextScreen =
"scores"
A l'initialisation de l'écran, on écrit le texte de fin de jeu.
' 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)
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.
[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.
'------------------------------------------------------------------------
' 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.
' 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).
' 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.
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
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.
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.
' 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 :
' 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.
' 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 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.
' 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.
' 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.
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.
XIX. Développement de l'écran des crédits▲
On crée l'écran comme on l'a fait pour tous les autres.
'***************************************************************************************
'* 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.
' 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
' 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.
' 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.
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.
'---------------------------------------------------------------------------------------
' 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.