XIV. Bilan à mi-parcours▲
Faisons un petit bilan pour y voir plus clair.
Nous avons terminé :
- l'écran de menu ;
- l'écran des options.
Il nous reste :
- l'écran des scores ;
- l'écran des crédits ;
- les écrans de fin de partie (gagné / perdu) ;
- et l'écran de jeu !
On constate après tout ce temps que nous n'avons pas encore vraiment commencé le développement du jeu.
Pour l'instant on ne voit pas franchement que nous sommes en train de créer un PacMan.
Par contre tout est prêt pour continuer le développement dans de bonnes conditions.
Pour la suite du tutoriel, nous allons enfin commencer le développement de l'écran de jeu.
XV. Développement de l'écran de jeu▲
L'écran de jeu est développé dans le module clScreenGame.
Ce sera bien entendu le plus complexe des écrans du jeu.
XV-A. Création de l'écran de jeu▲
Préparez le module clScreenGame 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 (40 images par seconde pour le jeu).
'------------------------------------------------------------------------
' 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
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
Case
"game"
Set
oScreen =
Nothing
Set
oScreen =
New
ClScreenGame
On teste la valeur « game » car dans l'écran de menu c'est cette valeur qu'on utilise lors du click sur Commencer le jeu.
XV-B. Chargement du tableau de jeu▲
On a défini le tableau de jeu dans la feuille Jeu.
Ce tableau fait 28 colonnes et 30 lignes.
On va stocker les valeurs de ce tableau dans une variable du module clScreenGame.
' Tableau de jeu
Private
gTableau
(
0
To
27
, 0
To
29
) As
String
Puis on charge les données de la feuille Jeu dans ce tableau.
' Compteurs
Dim
lCptY As
Integer
Dim
lCptX As
Integer
' Charge les données du tableau
With
ThisWorkbook.Sheets
(
"Jeu"
)
For
lCptX =
1
To
28
For
lCptY =
1
To
30
gTableau
(
lCptX -
1
, lCptY -
1
) =
.Cells
(
lCptY, lCptX).Value
Next
Next
End
With
XV-C. Affichage du tableau de jeu▲
Le tableau de jeu est dessiné en fonction du contenu des cases, à base de lignes et d'arcs de cercle.
Pour rappel, le tableau de jeu a été chargé dans gTableau à partir des données de la feuille Jeu.
Pour chaque case, on va lire les valeurs des cases adjacentes pour déterminer le type de trait à dessiner.
Créons donc une petite fonction de lecture du contenu d'une case.
'---------------------------------------------------------------------------------------
' Lecture du contenu d'une case
'---------------------------------------------------------------------------------------
' pX,pY : Coordonnées de la case
' La fonction renvoie le contenu de la case dans un string
' Si on dépasse le tableau, renvoit ""
'---------------------------------------------------------------------------------------
Private
Function
GetValue
(
pX As
Integer
, pY As
Integer
) As
String
On
Error
Resume
Next
' Lecture de la case dans le tableau représentant le niveau
GetValue =
gTableau
(
pX, pY)
If
Err
.Number
<>
0
Then
GetValue =
""
' Renvoit une chaîne vide si erreur
End
Function
Cette fonction renvoit le contenu de la case de coordonnées pX, pY.
Si les coordonnées n'appartiennent pas au tableau, une chaîne vide est renvoyée.
Ceci nous permettera de nous passer d'un test pour vérifier si la case est bien contenue dans le tableau.
Ensuite, pour dessiner les murs sur l'image, il nous faut connaître le centre de la case.
'---------------------------------------------------------------------------------------
' Calcul la position sur l'image en fonction de la position dans le tableau
'---------------------------------------------------------------------------------------
' pX,pY : Coordonnées dans le tableau
' pXOut,pYOut : Coordonnées sur l'image en pixel
'---------------------------------------------------------------------------------------
Private
Sub
GetCenter
(
pX As
Currency, pY As
Currency, pXOut As
Long
, pYOut As
Long
)
pXOut =
gBordure +
(
pX +
0
.5
) *
gTx
pYOut =
gBordure +
(
pY +
0
.5
) *
gTy
End
Sub
Le centre d'une case est déterminé en fonction de la taille des cases et de la bordure.
On a donc besoin de déclarer ces variables, qui seront ensuite calculées à l'initialisation de l'écran.
' Taille d'une case
Private
gTx As
Long
, gTy As
Long
' Bordure en pixels
Private
gBordure As
Long
A l'initialisation de l'écran, nous allons dessiner le contenu statique : c'est-à-dire le tableau de jeu.
' Position du centre de la case
Dim
lX As
Long
Dim
lY As
Long
' Valeur des cases adjacente
Dim
lUp As
String
Dim
lDown As
String
Dim
lRight As
String
Dim
lLeft As
String
' Valeur de la case
Dim
lValue As
String
' Dessine le contenu statique
With
oGdi
' Nouveau bitmap pour dessiner
.CreateBitmapForControl
FormGame.Img
' Dessin lissé pour les ellipses/lignes ...
.SmoothingMode
=
GdipSmoothingAntialias
' Début et fin de traits arrondis
.LineStart
=
LineCapRound
.LineEnd
=
LineCapRound
' Bordure de 5 pixels
gBordure =
5
' Taille des cases
gTx =
(
.ImageWidth
-
2
*
gBordure) \
28
gTy =
(
.ImageHeight
-
2
*
gBordure) \
30
' On s'assure que la taille des cases est un multiple de 2
gTx =
gTx -
(
gTx Mod
2
)
gTy =
gTy -
(
gTy Mod
2
)
' Fond noir
.FillColor
vbBlack
' On dessine les murs
For
lCptY =
0
To
29
' 30 lignes
For
lCptX =
0
To
27
' 28 colonnes
' Calcul du centre de la case de coordonnéex lcptx,lcpty
GetCenter CSng
(
lCptX), CSng
(
lCptY), lX, lY
' Lecture du contenu de la case
lValue =
GetValue
(
lCptX, lCptY)
' Lecture du contenu des cases adjacentes
lRight =
GetValue
(
lCptX +
1
, lCptY)
lLeft =
GetValue
(
lCptX -
1
, lCptY)
lUp =
GetValue
(
lCptX, lCptY -
1
)
lDown =
GetValue
(
lCptX, lCptY +
1
)
Select
Case
lValue
' Il y a un mur dans la case
Case
"X"
' Mur horizontal
If
lRight =
"X"
And
lLeft =
"X"
And
(Not
lUp =
"X"
Or
Not
lDown =
"X"
Or
Not
lRight =
"X"
) Then
.DrawLine
lX -
gTx /
2
, lY, lX +
gTx /
2
, lY, RGB
(
0
, 0
, 255
), 3
End
If
' Mur vertical
If
lUp =
"X"
And
lDown =
"X"
And
(Not
lRight =
"X"
Or
Not
lLeft =
"X"
) Then
.DrawLine
lX, lY -
gTy /
2
, lX, lY +
gTy /
2
, RGB
(
0
, 0
, 255
), 3
End
If
' Mur en haut et à droite mais pas ailleurs
If
lUp =
"X"
And
lRight =
"X"
And
lLeft <>
"X"
And
lDown <>
"X"
Then
.DrawEllipse
lX +
gTx /
2
, lY -
gTy /
2
, gTx /
2
, gTy /
2
, _
1
, -
1
, RGB
(
0
, 0
, 255
), 3
, , 180
, -
90
End
If
' Murs en coin (arrondis)
' Mur en haut et à gauche mais pas ailleurs
If
lUp =
"X"
And
lLeft =
"X"
And
lRight <>
"X"
And
lDown <>
"X"
Then
.DrawEllipse
lX -
gTx /
2
, lY -
gTy /
2
, gTx /
2
, gTy /
2
, _
1
, -
1
, RGB
(
0
, 0
, 255
), 3
, , 90
, -
90
End
If
' Mur en bas et à droite mais pas ailleurs
If
lDown =
"X"
And
lRight =
"X"
And
lLeft <>
"X"
And
lUp <>
"X"
Then
.DrawEllipse
lX +
gTx /
2
, lY +
gTy /
2
, gTx /
2
, gTy /
2
, _
1
, -
1
, RGB
(
0
, 0
, 255
), 3
, , -
180
, 90
End
If
' Mur en bas et à gauche mais pas ailleurs
If
lDown =
"X"
And
lLeft =
"X"
And
lRight <>
"X"
And
lUp <>
"X"
Then
.DrawEllipse
lX -
gTx /
2
, lY +
gTy /
2
, gTx /
2
, gTy /
2
, _
1
, -
1
, RGB
(
0
, 0
, 255
), 3
, , -
90
, 90
End
If
Case
Else
' La case ne contient pas un mur mais est dans un angle formé par deux murs
' On dessine un coin arrondi
' Mur en haut et à droite mais pas sur les deux autres côtés à la fois
If
lUp =
"X"
And
lRight =
"X"
And
Not
(
lLeft =
"X"
And
lDown =
"X"
) Then
.DrawEllipse
lX +
gTx /
2
, lY -
gTy /
2
, gTx /
2
, gTy /
2
, _
1
, -
1
, RGB
(
0
, 0
, 255
), 3
, , 0
, -
90
End
If
' Mur en haut et à gauche mais pas sur les deux autres côtés à la fois
If
lUp =
"X"
And
lLeft =
"X"
And
Not
(
lRight =
"X"
And
lDown =
"X"
) Then
.DrawEllipse
lX -
gTx /
2
, lY -
gTy /
2
, gTx /
2
, gTy /
2
, _
1
, -
1
, RGB
(
0
, 0
, 255
), 3
, , -
90
, -
90
End
If
' Mur en bas et à droite mais pas sur les deux autres côtés à la fois
If
lDown =
"X"
And
lRight =
"X"
And
Not
(
lLeft =
"X"
And
lUp =
"X"
) Then
.DrawEllipse
lX +
gTx /
2
, lY +
gTy /
2
, gTx /
2
, gTy /
2
, _
1
, -
1
, RGB
(
0
, 0
, 255
), 3
, , 0
, 90
End
If
' Mur en bas et à gauche mais pas sur les deux autres côtés à la fois
If
lDown =
"X"
And
lLeft =
"X"
And
Not
(
lRight =
"X"
And
lUp =
"X"
) Then
.DrawEllipse
lX -
gTx /
2
, lY +
gTy /
2
, gTx /
2
, gTy /
2
, _
1
, -
1
, RGB
(
0
, 0
, 255
), 3
, , 90
, 90
End
If
End
Select
Next
Next
End
With
On commence par créer une image avec CreateBitmap.
Cette image est remplie de noir, le jeu se déroulant sur fond noir.
La propriété DrawSmooth permet de lisser les dessins de traits.
Les propriétés LineStart et LineEnd définissent le type de début et fin de trait.
La bordure est définie à 5 pixels (pour éviter que le dessin soit « collé » aux bords de l'image).
Puis on calcule la taille de chaque case, en fonction de la taille de l'image, du nombre de cases, et de la bordure.
Notez qu'on s'assure que la taille des cases soit un multiple de 2 pour éviter des décalages dus à des arrondis.
Puis on dessine chaque mur (case contenant « X ») en fonction du contenu des cases adjacentes.
Pour chaque cas rencontré, on peut faire un petit dessin pour mieux visualiser le type de mur à dessiner.
Par exemple pour le troisième cas avec un mur dans la case.
' Mur en haut et à droite mais pas ailleurs
If
lUp =
"X"
And
lRight =
"X"
And
lLeft <>
"X"
And
lDown <>
"X"
Then
.DrawEllipse
lX +
gTx /
2
, lY -
gTy /
2
, gTx /
2
, gTy /
2
, _
1
, -
1
, RGB
(
0
, 0
, 255
), 3
, , 180
, -
90
S'il y a un mur en haut et un mur à droite, mais pas de mur sur les autres cases adjacentes :
On doit donc dessiner un arc centré sur le point (lX + gTx / 2, lY - gTy / 2), qui démarre à 180° et qui parcours 90°.
On procède de même pour gérer tous les cas possibles.
On obtient enfin le dessin des murs.
Ensuite on dessine les pastilles.
Les pastilles sont dessinées dans le contenu statique, même si elles devront disparaître de l'affichage.
En effet, on ne va pas redessiner les pastilles à chaque affichage.
On supprimera les pastilles de ce contenu statique en noircissant la case au fur et à mesure qu'elles seront mangées.
Pour l'occasion on crée une variable en-tête de module qui contient le nombre de pastilles du niveau.
Cette variable est initialisée au chargement de l'écran avec le nombre de pastilles dessinées.
Puis elle sera décrémentée durant le jeu.
Une fois la variable égale à zéro, cela signifiera que toutes les pastilles auront été mangées.
' Nombre de pastilles
Private
gNbPastilles As
Integer
Les pastilles sont représentées par des ellipses blanches.
Les super-pastilles ont un rayon plus important.
' On dessine les pastilles
' Pas de pastilles sur les bords du niveau, on commence à 1 et on termine 1 case avant la fin
' Initialise le décompte de pastille du niveau
gNbPastilles =
0
' Boucle sur le tableau
For
lCptY =
1
To
28
For
lCptX =
1
To
26
' Calcul du centre de la case pour y placer la pastille
GetCenter CSng
(
lCptX), CSng
(
lCptY), lX, lY
' Contenu de la case
lValue =
GetValue
(
lCptX, lCptY)
Select
Case
lValue
' Il y a une pastille dans la case
Case
"o"
' Ellipse de deux pixels de rayon
.DrawEllipse
lX, lY, 2
, 2
, 1
, vbWhite
, vbWhite
gNbPastilles =
gNbPastilles +
1
' Il y a une super-pastille dans la case
Case
"O"
' Ellipse de quatre pixels de rayon
.DrawEllipse
lX, lY, 4
, 4
, 1
, vbWhite
, vbWhite
gNbPastilles =
gNbPastilles +
1
End
Select
Next
Next
' On conserve le dessin du niveau avec ses murs et ses pastilles
.ImageKeep
Notez qu'on conserve ce contenu statique avec un appel à ImageKeep une fois le dessin terminé.
On obtient le dessin des murs et des pastilles.
XV-D. Chargement des ressources▲
A l'initialisation de l'écran, nous devons charger les ressources, c'est-à-dire les images et les sons.
' Chargement des images du PacMan
Dim
lCpt As
Integer
With
oGdi.ImgNew
(
"pac0"
)
.LoadFile
ThisWorkbook.Path
&
"\images\pac0.png"
.Resize
gTx
End
With
For
lCpt =
1
To
3
With
oGdi.ImgNew
(
"pacg"
&
lCpt)
.LoadFile
ThisWorkbook.Path
&
"\images\pacg"
&
lCpt &
".png"
.Resize
gTx
End
With
With
oGdi.ImgNew
(
"pach"
&
lCpt)
.LoadFile
ThisWorkbook.Path
&
"\images\pach"
&
lCpt &
".png"
.Resize
gTx
End
With
With
oGdi.ImgNew
(
"pacd"
&
lCpt)
.LoadFile
ThisWorkbook.Path
&
"\images\pacd"
&
lCpt &
".png"
.Resize
gTx
End
With
With
oGdi.ImgNew
(
"pacb"
&
lCpt)
.LoadFile
ThisWorkbook.Path
&
"\images\pacb"
&
lCpt &
".png"
.Resize
gTx
End
With
Next
' Chargement des images des fantômes en état "normal"
With
oGdi.ImgNew
(
"ghost1"
)
.LoadFile
ThisWorkbook.Path
&
"\images\fantome.png"
With
oGdi.ImgClone
(
"ghost1"
, "ghost2"
)
.ReplaceColor
vbRed
, vbGreen
.Resize
gTx
End
With
With
oGdi.ImgClone
(
"ghost1"
, "ghost3"
)
.ReplaceColor
vbRed
, vbYellow
.Resize
gTx
End
With
.Resize
gTx
End
With
' Chargement de l'images des fantômes en état "effrayé"
With
oGdi.ImgNew
(
"ghostscared"
)
.LoadFile
ThisWorkbook.Path
&
"\images\fantomeeffraye.png"
.ReplaceColor
vbBlack
, vbBlack
, , 0
End
With
' Chargement de l'images des yeux de fantômes pour le retour au centre
With
oGdi.ImgNew
(
"yeux"
)
.LoadFile
ThisWorkbook.Path
&
"\images\yeux.png"
.ReplaceColor
vbBlack
, vbBlack
, , 0
End
With
' Chargement des sons
oSound.OpenSound
ThisWorkbook.Path
&
"\sons\aie.wav"
, "aie"
oSound.OpenSound
ThisWorkbook.Path
&
"\sons\aouch.wav"
, "aouch"
oSound.OpenSound
ThisWorkbook.Path
&
"\sons\blip.wav"
, "blip"
Les images sont chargées dans l'objet oGdi.
Chaque image est identifiée par une chaîne de caractères.
On redimensionne au chargement chaque image à la taille d'une case (avec le paramètre pWidth = gTx).
Pour les fantômes, on génère trois images, en modifiant la couleur rouge pour obtenir 3 fantômes de couleur différente.
Attention à modifier la couleur avant le redimensionnement qui, avec le lissage de l'image va un peu mélanger les couleurs.
Les sons sont chargés dans l'objet oSound, identifiés également par une chaîne de caractères.
XV-E. Création de du module objet clSprite▲
Nous allons dans le jeu avoir à gérer deux types d'objets : le PacMan et les fantômes.
Ces objets sont similaires, ce sont tout simplement des sprites.
Les données du Pacman et de chaque fantôme seront stockées dans un objet de type clSprite qui contient :
- leur position ;
- leur mouvement ;
- le mouvement suivant ;
- leur vitesse ;
- un compteur d'image (utilisé pour l'animation du PacMan et pour les couleurs de fantômes).
Créez donc un module de classe nommé clSprite.
'***************************************************************************************
'* CLASSE POUR SPRITE
'***************************************************************************************
Option
Explicit
' Position
Public
X As
Currency
Public
Y As
Currency
' Mouvement (g,d,h,b, ou vide si arrêté)
Public
Mvt As
String
' Mouvement en attente (entre deux cases)
Public
MvtSuivant As
String
' Numéro de l'image
Public
Img As
Integer
' Vitesse
Public
Vitesse As
Currency
On utilise pour la position et la vitesse un type de données Currency car en VBA ce type permet de gérer correctement des valeurs non entières.
Les types Single ou Double ne conviendraient pas car VBA arrondi ces valeurs.
Ainsi un sprite en position X = 10.4 se trouvera entre la colonne 10 et 11.
Lorsque le sprite atteint la position 11, on sait que le sprite est au centre d'une colonne.
Les mouvements sont des lettres :
- g pour gauche ;
- d pour droite ;
- h pour haut ;
- b pour bas.
Il n'y a pas de mouvement possible en diagonale.
On utilise une variable MvtSuivant pour stocker le mouvement suivant.
Ainsi lorsque le joueur appuie sur une touche, on détecte le mouvement demandé que l'on stocke dans cette variable.
Le sprite continue son chemin jusqu'à atteindre une case « pleine » (positions X et Y entières) et on modifie alors son mouvement.
De cette manière le joueur peut demander le déplacement du sprite sans avoir à appuyer sur la touche de direction pile au moment où le sprite atteint le centre d'une case.
XV-F. Gestion du Pacman▲
Le Pacman est donc un objet de type clSprite.
Déclarez cet objet dans le module clScreenGame
' Objet Pacman
Private
oPacman As
clSprite
A l'initialisation de l'écran de jeu, on va créer l'objet Pacman et lui donner ses paramètres par défaut.
' Initialisation du Pacman
Set
oPacman =
New
clSprite
' Pac immobile par défaut
oPacman.Mvt
=
""
oPacman.MvtSuivant
=
""
' Initialise la position de départ
oPacman.X
=
14
oPacman.Y
=
22
' Image initial du Pac
oPacman.Img
=
0
' Vitesse initiale du Pac
oPacman.Vitesse
=
0
.1
Au début du jeu, le PacMan est immobile.
Il n'y a pas de mouvement.
Par contre on initialise sa vitesse qui est d'un dixième de case.
On le place au départ vers le bas au centre (colonne 14, ligne 22).
Pour dessiner le PacMan à l'écran, on va placer le code de dessin dans la fonction ClScreen_UpdateScreen.
On commence par restaurer le contenu statique, puis on affichage l'image du PacMan.
L'affichage d'une image se fait à l'aide de la fonction DrawImg de l'objet oGdi.
On utilise la fonction GetCenter pour calculer la position du centre du PacMan, puis on affiche l'image.
(Notez qu'on a défini les paramètres de GetCenter en Currency pour pouvoir passer des paramètres non entiers).
' Position sur le dessin
Dim
lX As
Long
, lY As
Long
' Affichage
' Reprend l'image de la mémoire
oGdi.ImageReset
' Calcule le centre du PacMan
GetCenter oPacman.X
, oPacman.Y
, lX, lY
' Dessine le PacMan
oGdi.DrawImg
"pac"
&
IIf
(
oPacman.Img
=
0
, ""
, oPacman.Mvt
) &
oPacman.Img
, lX, lY, , , , GdipSizeModeautosize
Dans la fonction DrawImg, le paramètre GdipSizeModeautosize signifie qu'on affiche l'image sans redimensionnement et centrée sur les deux premières coordonnées.
L'image du PacMan à afficher est fonction de son mouvement.
Si le PacMan est en mouvement (paramètre Mvt non vide, différent de "") alors l'image du PacMan est pac[Mvt][Img].
Si le PacMan est immobile, l'image est pac0.
Par exemple pour un mouvement vers la droite, les images seront :
- pac0 ;
- pacd1 ;
- pacd2 ;
- pacd3.
Si on affiche le formulaire, on visualise alors le PacMan, sagement immobile.
Il faut maintenant tester l'appui de touche afin de modifier le mouvement du PacMan.
Dim
lDown As
Boolean
, lUp As
Boolean
, lLeft As
Boolean
, lRight As
Boolean
' Test directions du joystick
oCommand.TestJoypadDir
lLeft, lRight, lUp, lDown
' Test des commandes de déplacement du Pacman
If
oCommand.TestKey
(
oSharedData.ToucheBas
) Or
lDown Then
oPacman.MvtSuivant
=
"b"
End
If
If
oCommand.TestKey
(
oSharedData.ToucheDroite
) Or
lRight Then
oPacman.MvtSuivant
=
"d"
End
If
If
oCommand.TestKey
(
oSharedData.ToucheGauche
) Or
lLeft Then
oPacman.MvtSuivant
=
"g"
End
If
If
oCommand.TestKey
(
oSharedData.ToucheHaut
) Or
lUp Then
oPacman.MvtSuivant
=
"h"
End
If
Comme prévu, on modifie le paramètre MvtSuivant de l'objet Pacman.
Dans la fonction de mise à jour de l'écran, on modifie la position du PacMan en fonction de son mouvement.
Puis on teste si le PacMan est sur une case « pleine » (positions entière) pour remplacer le mouvement en cours par le mouvement suivant.
On effectue le déplacement des sprites avant leur dessin, donc en début de fonction.
' Déplacement du PacMan en fonction de son mouvement et sa vitesse
Select
Case
oPacman.Mvt
Case
"d"
oPacman.X
=
oPacman.X
+
oPacman.Vitesse
Case
"g"
oPacman.X
=
oPacman.X
-
oPacman.Vitesse
Case
"h"
oPacman.Y
=
oPacman.Y
-
oPacman.Vitesse
Case
"b"
oPacman.Y
=
oPacman.Y
+
oPacman.Vitesse
End
Select
' Si le PacMan atteint une case "pleine" => modifie le mouvement en fonction du mouvement suivant demandé
If
oPacman.X
=
Int
(
oPacman.X
) And
oPacman.Y
=
Int
(
oPacman.Y
) Then
' Mouvement suivant
oPacman.Mvt
=
oPacman.MvtSuivant
End
If
Il manque l'animation du PacMan.
' Animation du PacMan
' On tourne sur 4 images
If
oPacman.Mvt
=
""
Then
' Si PacMan immobile => image 0
oPacman.Img
=
0
Else
oPacman.Img
=
(
oPacman.Img
+
1
) Mod
4
End
If
Le déplacement du PacMan fonctionne correctement, sauf qu'il peut traverser les murs.
Il faut donc tester s'il y a un mur dans la direction du mouvement suivant et annuler le mouvement si nécessaire.
On empêche également que le PacMan ne traverse la porte au centre d'où les fantômes sortent.
Et enfin on en profite pour gérer le passage d'un côté à l'autre du jeu si le Pacman est sur une case contenant « P » (pour simplifier le tutoriel, on met les valeurs du passage « en dur » = colonne 27 ou 0).
On a besoin de déclarer quelques variables qui contiendront le contenu des cases.
' Valeur des cases et des alentours
Dim
lCase
As
String
Dim
lUp As
String
Dim
lDown As
String
Dim
lRight As
String
Dim
lLeft As
String
' Si le PacMan atteint une case "pleine" => modifie le mouvement en fonction du mouvement suivant demandé
If
oPacman.X
=
Int
(
oPacman.X
) And
oPacman.Y
=
Int
(
oPacman.Y
) Then
' Contenu des cases
lCase
=
GetValue
(
oPacman.X
, oPacman.Y
)
lRight =
GetValue
(
oPacman.X
+
1
, oPacman.Y
)
lLeft =
GetValue
(
oPacman.X
-
1
, oPacman.Y
)
lUp =
GetValue
(
oPacman.X
, oPacman.Y
-
1
)
lDown =
GetValue
(
oPacman.X
, oPacman.Y
+
1
)
' Passage d'un côté à l'autre du jeu
If
lCase
=
"P"
Then
If
oPacman.X
=
0
Then
oPacman.X
=
27
ElseIf
oPacman.X
=
27
Then
oPacman.X
=
0
End
If
End
If
' Mouvement suivant
oPacman.Mvt
=
oPacman.MvtSuivant
' Teste si le mouvement suivant est possible
If
oPacman.Mvt
=
"d"
And
lRight =
"X"
Then
oPacman.Mvt
=
""
End
If
If
oPacman.Mvt
=
"g"
And
lLeft =
"X"
Then
oPacman.Mvt
=
""
End
If
If
oPacman.Mvt
=
"b"
And
(
lDown =
"X"
Or
lDown =
"_"
) Then
oPacman.Mvt
=
""
End
If
If
oPacman.Mvt
=
"h"
And
lUp =
"X"
Then
oPacman.Mvt
=
""
End
If
End
If
Le Pacman peut maintenant être déplacé correctement dans tout le jeu.
XV-G. Gestion des pastilles▲
Les pastilles sont mangées par le PacMan.
Lorsqu'une pastille est mangée, on noirci la case en noir sur le contenu statique puis on resauvegarde ce contenu.
Il faut donc déplacer l'appel à la fonction ImageReset en début de fonction ClScreen_UpdateScreen, après les déclarations.
En effet on va :
- d'abord restaurer le contenu statique ;
- puis tester si le PacMan mange une pastille et la supprimer de l'affichage ;
- et enfin on dessinera les sprites.
' Reprend l'image de la mémoire
oGdi.ImageReset
Lorsque le Pacman atteint une case pleine, on va alors tester si c'est une pastille et la supprimer de l'affichage.
On supprime également la pastille du tableau, et on joue un son.
Et enfin on décrémente le compteur de pastille et on ajoute 1 au score.
Pour le score, il faut ajouter une variable partagée dans clSharedData.
' Score
Public
Score As
Long
' Si le PacMan atteint une case "pleine" => modifie le mouvement en fonction du mouvement suivant demandé
If
oPacman.X
=
Int
(
oPacman.X
) And
oPacman.Y
=
Int
(
oPacman.Y
) Then
' Contenu des cases
lCase
=
GetValue
(
oPacman.X
, oPacman.Y
)
lRight =
GetValue
(
oPacman.X
+
1
, oPacman.Y
)
lLeft =
GetValue
(
oPacman.X
-
1
, oPacman.Y
)
lUp =
GetValue
(
oPacman.X
, oPacman.Y
-
1
)
lDown =
GetValue
(
oPacman.X
, oPacman.Y
+
1
)
' Mange une pastille
If
lCase
=
"o"
Or
lCase
=
"O"
Then
' Calcule le centre de la pastille
GetCenter oPacman.X
, oPacman.Y
, lX, lY
' Noirci la case
oGdi.DrawRectangle
lX -
gTx /
2
, lY -
gTy /
2
, lX +
gTx /
2
, lY +
gTy /
2
, vbBlack
, vbBlack
' Supprime la pastille du tableau
gTableau
(
oPacman.X
, oPacman.Y
) =
""
' Joue un son
oSound.PlaySound
"blip"
' Décrémente le compteur de pastille
gNbPastilles =
gNbPastilles -
1
' Incrémente le score
oSharedData.Score
=
oSharedData.Score
+
1
' Sauvegarde le contenu "statique"
oGdi.ImageKeep
End
If
[...
]
Pour visualiser le score, on ajoute un code de dessin à la fin de la fonction ClScreen_UpdateScreen.
' Affiche le score
oGdi.DrawText
"Score : "
&
oSharedData.Score
, 20
, , 0
, 0
, _
oGdi.ImageWidth
, oGdi.ImageHeight
, 2
, 2
, vbRed
, , _
RGB
(
255
, 255
, 100
)
Le Pacman peut maintenant manger les pastilles, et on voit le score en bas à droite s'incrémenter à chaque pastille.
XV-H. Gestion des fantômes▲
Les fantômes sont également des objets de type clSprite.
Mais il y a plusieurs fantômes, dont le nombre est défini dans les options.
Nous allons donc déclarer et initialiser une collection de fantômes.
' Collection de fantômes
Private
oCollFantomes As
Collection
' Compteur
Dim
lCpt As
Long
' Objet Fantome
Dim
lFantome As
clSprite
' Initialisation des fantômes
Set
oCollFantomes =
New
Collection
If
oCollFantomes Is
Nothing
Then
For
lCpt =
1
To
oSharedData.NbFantomes
Set
lFantome =
New
clSprite
' Position initiale des fantôme
lFantome.X
=
Int
(
11
+
Rnd
*
6
) ' Colonne entre 11 et 16
lFantome.Y
=
14
' Ligne 14
' Image (on tourne sur trois images pour changer la couleur)
lFantome.img
=
1
+
(
lCpt Mod
3
)
' Vitesse initiale des fantômes
lFantome.Vitesse
=
0
.1
' Ajout à la collection
oCollFantomes.Add
lFantome
Next
End
If
Si on affiche le formulaire on obtient une erreur d'exécution '91' : Variable objet ou variable de bloc With non définie.
Cette erreur est levée lorsqu'on essaye de lire le nombre de fantôme de l'objet oSharedData.
En effet à l'initialisation de l'écran, l'objet oSharedData n'est pas encore affecté.
Et malheureusement VBA ne permet pas de passer des paramètres au constructeur de la classe.
Il faut alors déplacer ce code d'initialisation des fantômes dans la fonction ClScreen_UpdateScreen, au début après les déclarations.
On vérifie que la collection de fantômes n'est pas initialisée afin de ne le faire qu'une seule fois.
' Compteur
Dim
lCpt As
Long
' Objet Fantome
Dim
lFantome As
clSprite
' Initialisation des fantômes
If
oCollFantomes Is
Nothing
Then
' une seule initialisation
Set
oCollFantomes =
New
Collection
For
lCpt =
1
To
oSharedData.NbFantomes
Set
lFantome =
New
clSprite
' Position initiale des fantôme
lFantome.X
=
Int
(
11
+
Rnd
*
6
) ' Colonne entre 11 et 16
lFantome.Y
=
14
' Ligne 14
' Image (on tourne sur trois images)
lFantome.Img
=
1
+
(
lCpt Mod
3
)
' Vitesse initiale des fantômes
lFantome.Vitesse
=
0
.1
' Ajout à la collection
oCollFantomes.Add
lFantome
Next
End
If
On va ensuite gérer le déplacement et l'affichage des fantômes après le déplacement et l'affichage du Pacman dans la fonction ClScreen_UpdateScreen.
Etant donné qu'il y a plusieurs fantômes, on doit faire une boucle pour gérer chaque fantôme de la collection.
Comme pour le Pacman, on va d'abord déplacer le fantôme en fonction de sa vitesse.
Puis si le fantôme est sur une case « pleine » (positions entières), on recherche le mouvement à affecter au fantôme.
Dans le cas des fantômes, on n'utilise pas le paramètre MvtSuivant qui n'aurait pas d'intérêt.
Le mouvement des fantômes doit répondre aux règles suivantes :
- Le fantôme doit se rapprocher du PacMan => on recherche donc l'axe où la distance entre le fantôme et le PacMan est la plus grande (X ou Y).
- Si le fantôme est sur la porte de sortie (repérée "_"), alors il se déplace vers le haut (afin d'éviter de sortir et rentrer sans cesse).
- Le fantôme ne peut pas rentrer par la porte au centre de l'écran (repérée »_"), il ne peut que sortir.
- Si on n'a pas pû déterminer le déplacement optimal du fantôme, on lui donne un mouvement aléatoire.
- Le fantôme ne peut pas se déplacer sur un mur ("X »), ou sur un des 2 passages ("P").
Et enfin on dessine le fantôme, de la même manière qu'on a dessiné le PacMan.
Pour un fantôme, l'image est ghost1, ghost2 ou ghost3 en fonction du paramètre Img du fantôme.
' Variable pour numéro de fantôme
Dim
lCalc as
long
' Gestion des fantômes
For
Each
lFantome In
oCollFantomes
' Déplacement des fantômes
Select
Case
lFantome.Mvt
Case
"d"
lFantome.X
=
lFantome.X
+
lFantome.Vitesse
Case
"g"
lFantome.X
=
lFantome.X
-
lFantome.Vitesse
Case
"h"
lFantome.Y
=
lFantome.Y
-
lFantome.Vitesse
Case
"b"
lFantome.Y
=
lFantome.Y
+
lFantome.Vitesse
End
Select
' Test si le fantôme est sur une case "pleine"
If
Int
(
lFantome.X
) =
lFantome.X
And
Int
(
lFantome.Y
) =
lFantome.Y
Then
' Lecture du contenu des cases aux alentours du fantôme
lRight =
GetValue
(
lFantome.X
+
1
, lFantome.Y
)
lLeft =
GetValue
(
lFantome.X
-
1
, lFantome.Y
)
lUp =
GetValue
(
lFantome.X
, lFantome.Y
-
1
)
lDown =
GetValue
(
lFantome.X
, lFantome.Y
+
1
)
' Pas de mouvement par défaut
lFantome.Mvt
=
""
' Recherche du mouvement pour se rapprocher du PacMan
' Si distance X plus grand que distance Y
If
Abs
(
lFantome.X
-
oPacman.X
) >
Abs
(
lFantome.Y
-
oPacman.Y
) Then
If
lFantome.X
<
oPacman.X
And
lRight <>
"X"
And
lRight <>
"P"
Then
lFantome.Mvt
=
"d"
ElseIf
lFantome.X
>=
oPacman.X
And
lLeft <>
"X"
And
lLeft <>
"P"
Then
lFantome.Mvt
=
"g"
End
If
End
If
' Si distance Y plus grand que distance X ou que le cas précédent n'a pas donné de mouvement possible
If
lFantome.Mvt
=
""
Then
If
lFantome.Y
<
oPacman.Y
And
lDown <>
"X"
And
lDown <>
"_"
Then
lFantome.Mvt
=
"b"
ElseIf
lFantome.Y
>=
oPacman.Y
And
lUp <>
"X"
Then
lFantome.Mvt
=
"h"
End
If
End
If
' Si on est sur la porte de sortie => déplacement vers le haut
If
GetValue
(
lFantome.X
, lFantome.Y
) =
"_"
Then
lFantome.Mvt
=
"h"
' Si fantôme immobile => mouvement aléatoire pour le lancer
If
lFantome.Mvt
=
""
Then
lCalc =
1
+
Int
(
Rnd
*
4
)
Select
Case
lCalc
Case
1
: lFantome.Mvt
=
"d"
Case
2
: lFantome.Mvt
=
"g"
Case
3
: lFantome.Mvt
=
"h"
Case
4
: lFantome.Mvt
=
"b"
End
Select
End
If
' Teste si le mouvement est possible, sinon on l'annule
If
lFantome.Mvt
=
"d"
And
(
lRight =
"X"
Or
lRight =
"P"
) Then
lFantome.Mvt
=
""
End
If
If
lFantome.Mvt
=
"g"
And
(
lLeft =
"X"
Or
lLeft =
"P"
) Then
lFantome.Mvt
=
""
End
If
If
lFantome.Mvt
=
"b"
And
(
lDown =
"X"
Or
lDown =
"_"
) Then
lFantome.Mvt
=
""
End
If
If
lFantome.Mvt
=
"h"
And
lUp =
"X"
Then
lFantome.Mvt
=
""
End
If
End
If
' Calcule le centre du fantôme
GetCenter lFantome.X
, lFantome.Y
, lX, lY
' Dessine le fantôme
oGdi.DrawImg
"ghost"
&
lFantome.Img
, lX, lY, , , , GdipSizeModeautosize
Next
Testez l'affichage du jeu, on voit bien les fantômes se déplacer.
Les fantômes sont plutôt stupides dans leur déplacement, mais il ne faudrait pas les rendre trop intelligents si on veut que le jeu soit jouable.
XV-I. Super-pastille : fantômes effrayés▲
Un élément essentiel du jeu est le changement d'état des fantômes.
Lorsque le Pacman mange une super-pastille (repérée par un « O » majuscule), les fantômes doivent changer d'état :
- ils deviennent bleus ;
- ils se déplacent plus lentement et fuient le PacMan ;
- ils sont mangeables.
Cet état est temporaire, on le fait durer 15 secondes.
Ajoutons un compteur pour l'état effrayé pour les objets fantômes
' Etat effrayé = temps restant
Public
Scared As
long
Lorsque le PacMan mangera une super-pastille, on initialise ce compteur.
On fait ce test après le premier test sur l'arrivé sur une pastille.
' Mange une pastille
If
lCase
=
"o"
Or
lCase
=
"O"
Then
[...
] ' Test déjà écrit, ajouter le test de super-pastille après celui-ci
End
If
' Mange une super-pastille
If
lCase
=
"O"
Then
' Pour chaque fantôme
For
Each
lFantome In
oCollFantomes
' Passe le fantôme à l'état effrayé durant 15 secondes
' On multiplie par 40 car 40 images par secondes
lFantome.Scared
=
40
*
15
Next
End
If
Ensuite dans le code de gestion des fantômes, on décrémente le compteur s'il est supérieur à zéro.
' Gestion des fantômes
For
Each
lFantome In
oCollFantomes
' Décrémente le compteur d'état effrayé
If
lFantome.Scared
>
0
Then
lFantome.Scared
=
lFantome.Scared
-
1
[...
]
Et on modifie la recherche de mouvement des fantômes pour les éloigner du PacMan s'ils sont effrayés.
' Pas de mouvement par défaut
lFantome.Mvt
=
""
' Recherche du mouvement pour se rapprocher du PacMan
If
lFantome.Scared
=
0
Then
' Si distance X plus grand que distance Y
If
Abs
(
lFantome.X
-
oPacman.X
) >
Abs
(
lFantome.Y
-
oPacman.Y
) Then
If
lFantome.X
<
oPacman.X
And
lRight <>
"X"
And
lRight <>
"P"
Then
lFantome.Mvt
=
"d"
ElseIf
lFantome.X
>=
oPacman.X
And
lLeft <>
"X"
And
lLeft <>
"P"
Then
lFantome.Mvt
=
"g"
End
If
End
If
' Si distance Y plus grand que distance X ou que le cas précédent n'a pas donné de mouvement possible
If
lFantome.Mvt
=
""
Then
If
lFantome.Y
<
oPacman.Y
And
lDown <>
"X"
And
lDown <>
"_"
Then
lFantome.Mvt
=
"b"
ElseIf
lFantome.Y
>=
oPacman.Y
And
lUp <>
"X"
Then
lFantome.Mvt
=
"h"
End
If
End
If
' Ou pour s'éloigner si le fantome est en état effrayé
Else
' Si distance X plus petite que distance Y
If
Abs
(
lFantome.X
-
oPacman.X
) <
Abs
(
lFantome.Y
-
oPacman.Y
) Then
If
lFantome.X
>
oPacman.X
And
lRight <>
"X"
And
lRight <>
"P"
Then
lFantome.Mvt
=
"d"
ElseIf
lFantome.X
<=
oPacman.X
And
lLeft <>
"X"
And
lLeft <>
"P"
Then
lFantome.Mvt
=
"g"
End
If
End
If
' Si distance Y plus petite que distance X ou que le cas précédent n'a pas donné de mouvement possible
If
lFantome.Mvt
=
""
Then
If
lFantome.Y
>
oPacman.Y
And
lDown <>
"X"
And
lDown <>
"_"
Then
lFantome.Mvt
=
"b"
ElseIf
lFantome.Y
<=
oPacman.Y
And
lUp <>
"X"
Then
lFantome.Mvt
=
"h"
End
If
End
If
End
If
Et enfin modifiez le code de dessin des fantômes pour afficher l'image fantomeeffraye si nécessaire.
' Dessine le fantôme
oGdi.DrawImg
"ghost"
&
IIf
(
lFantome.Scared
>
0
, "scared"
, lFantome.Img
), lX, lY, , , , GdipSizeModeautosize
Les fantômes sont maintenant bleus durant 15 secondes lorsque le PacMan mange une super-pastille.
Et ils s'éloignent au lieu de se rapprocher.
Par contre leur vitesse n'est pas modifiée.
Lors de la modification de la vitesse il faut bien faire attention.
En effet on teste l'arrivée du sprite sur une case en testant si les positions sont entières.
En modifiant la vitesse, on risque de ne plus arriver à des valeurs entières.
Par exemple :
La position X est égale à 9.95 et on modifie la vitesse de 0.05 à 0.1.
La position suivante vaudra alors 10.05 sans passer par la valeur entière 10.
Il faut donc ajuster la position en fonction de la vitesse définie.
Pour modifier la position lors de la modification de la vitesse, on va transformer la variable publique Vitesse en propriété.
Private
gVitesse As
Currency
' Propriété pour lecture et écriture de la vitesse
Public
Property
Get
Vitesse
(
) As
Currency
Vitesse =
gVitesse
End
Property
Public
Property
Let
Vitesse
(
pVitesse As
Currency)
gVitesse =
pVitesse
' Si vitesse non nulle
If
gVitesse <>
0
Then
' Déplace légérement le sprite pour se repositionner sur un multiple de la vitesse
X =
Int
(
X) +
Int
((
X -
Int
(
X)) /
gVitesse) *
gVitesse
Y =
Int
(
Y) +
Int
((
Y -
Int
(
Y)) /
gVitesse) *
gVitesse
End
If
End
Property
Pour que cela fonctionne, la vitesse doit être un dividende de 1 (exemple : 0.2 ou 0.1).
Une vitesse de 0.3 ou de 0.04 ne conviendrait pas.
Le PacMan a une vitesse constante de 0.1.
Les fantômes ont une vitesse de 0.1 en état normal, et de 0.05 en état effrayé.
La modification de la vitesse des fantômes va se faire également dans le module clSprite.
Lors de la modification du compteur Scared, on va modifier la vitesse des fantômes.
Pour cela il faut tranformer la variable publique Scared en propriété.
' Etat effrayé
Private
gScared As
Long
' Propriété pour lecture et écriture de l'état effrayé
Public
Property
Get
Scared
(
) As
Long
Scared =
gScared
End
Property
Public
Property
Let
Scared
(
pScared As
Long
)
If
gScared =
0
And
pScared <>
0
Then
' Passage à l'état effrayé => on passe la vitesse de 0.1 à 0.05
Vitesse =
gVitesse /
2
ElseIf
gScared <>
0
And
pScared =
0
Then
' Passage à l'état normal => on repasse la vitesse de à 0.1
Vitesse =
gVitesse *
2
End
If
gScared =
pScared
End
Property
Le passage des fantômes de l'état effrayé à l'état normal et vice-versa est terminé.
XV-J. Gestion des collisions entre les sprites▲
Pour simplifier, il n'y a pas de gestion de collisions entre les fantômes : ils se traversent.
Par contre il faut gérer la collision entre le PacMan et les fantômes.
On simplifie également la détection de collision entre les sprites en détectant la collision entre deux rectangles.
Il faudrait vérifier si un des 4 coins du rectangle encadrant un fantome se trouve dans le rectangle encadrant le PacMan.
Plutôt que de tester toutes ces coordonnées (ce ne serait cependant pas très compliqué), on va utiliser les régions de gdi+.
Lors du dessin des sprites (fantôme et PacMan), on va ajouter une région correspondant au rectangle dans lequel le sprite est dessiné.
Cela se fait simplement en rajoutant un paramètre à l'appel de la fonction DrawImg de l'objet oGdi.
Pour identifier le sprite, on va utiliser le pointeur de l'objet qui est déterminé avec ObjPtr.
Ce pointeur est garanti unique.
' Dessine le PacMan et ajoute une région rectangulaire
oGdi.DrawImg
"pac"
&
IIf
(
oPacman.img
=
0
, ""
, oPacman.Mvt
) &
oPacman.img
, lX, lY, , , , _
GdipSizeModeAutoSize, , , CStr
(
ObjPtr
(
oPacman))
' Dessine le fantôme et ajoute une région rectangulaire
oGdi.DrawImg
"ghost"
&
IIf
(
lFantome.Scared
>
0
, "scared"
, lFantome.img
), lX, lY, , , , _
GdipSizeModeAutoSize, , , CStr
(
ObjPtr
(
lFantome))
On va ensuite rechercher une éventuelle collision après avoir dessiner les sprites.
On profite de la boucle déjà en place sur la collection de fantômes.
Les collisions sont testées à l'aide de la fonction RegionsIntersect de l'objet oGdi.
Pour tester rapidement, on écrit un texte en bas à gauche lorsque le PacMan touche un fantôme.
' Gestion des fantômes
For
Each
lFantome In
oCollFantomes
[...
]
' Détection de collision avec le PacMan
If
oGdi.RegionsIntersect
(
ObjPtr
(
oPacman), ObjPtr
(
lFantome)) Then
oGdi.DrawText
"Collision"
, 20
, , 0
, 0
, oGdi.ImageWidth
, oGdi.ImageHeight
, 0
, 2
, vbRed
, , RGB
(
255
, 255
, 100
), , , , , , True
End
If
Next
Affichez le formulaire et allez au contact d'un fantôme pour visualiser la collision.
Que faire en cas de collision ?
Si le fantôme est en état normal => le PacMan est mangé => on affiche l'écran de jeu perdu.
Si le fantôme est en état effrayé => le fantôme est mangé => il doit retourner au centre.
Dans les deux cas, on joue un son.
Pour l'état normal c'est facile :
' Détection de collision avec le PacMan
If
oGdi.RegionsIntersect
(
ObjPtr
(
oPacman), ObjPtr
(
lFantome)) Then
If
lFantome.Scared
=
0
Then
' Le fantôme est en état normal => il mange le PacMan
' On joue un son
oSound.PlaySound
"aouch"
' On demande le changement d'écran vers l'écran de jeu perdu
gNextScreen =
"gameover"
gChangeScreen =
True
Else
' Le fantôme est en état effrayé => il est mangé
' Code à suivre
End
If
End
If
Pour l'état effrayé c'est plus compliqué :
Il faut définir une nouvelle propriété des sprites : un indicateur de retour au centre.
Lorsque cet indicateur est à Vrai :
- les fantômes doivent suivre le chemin pour retourner au centre ;
- ils sont accélérés pour un retour rapide ;
- seuls leurs yeux s'affichent ;
- ils ne doivent pas être remangés ou et ne doivent pas pouvoir manger le PacMan ;
- ils reviennent ensuite à l'état normal.
' Indicateur pour retour au centre
Private
gReturnToCentre As
Boolean
' Propriété pour lecture et écriture du retour au centre
Public
Property
Get
ReturnToCentre
(
) As
Boolean
ReturnToCentre =
gReturnToCentre
End
Property
Public
Property
Let
ReturnToCentre
(
pReturnToCentre As
Boolean
)
If
gReturnToCentre =
False
And
pReturnToCentre =
True
Then
' Met le flag de retour au centre => on passe la vitesse à 0.25
Vitesse =
0
.25
ElseIf
ReturnToCentre =
True
And
pReturnToCentre =
False
Then
' Annule le flag de retour au centre => on repasse la vitesse à 0.1
Vitesse =
0
.1
End
If
gReturnToCentre =
pReturnToCentre
End
Property
Modifions ensuite la détection des collisions.
Notez qu'on ajoute 50 points au score par fantôme mangé.
' Détection de collision avec le PacMan
' Pas de détection si retour au centre
If
Not
lFantome.ReturnToCentre
And
oGdi.RegionsIntersect
(
ObjPtr
(
oPacman), ObjPtr
(
lFantome)) Then
If
lFantome.Scared
=
0
Then
' Le fantôme est en état normal => il mange le PacMan
' On joue un son
oSound.PlaySound
"aouch"
' On demande le changement d'écran vers l'écran de jeu perdu
gNextScreen =
"gameover"
gChangeScreen =
True
Else
' Le fantôme est en état effrayé => il est mangé
' On joue un son
oSound.PlaySound
"aie"
' Incrémente le score de 50
oSharedData.Score
=
oSharedData.Score
+
50
' Fin de l'état effrayé
lFantome.Scared
=
0
' Retour au centre
lFantome.ReturnToCentre
=
True
End
If
End
If
Occupons maintenant du retour au centre des fantômes.
XV-K. Retour au centre des fantômes▲
Les déplacements à suivre pour le retour au centre ont été définis dans la feuille Chemin.
De la même manière que pour les données du tableau de la feuille Jeu, nous allons charger ces données dans un tableau.
' Tableau de retour au centre
Private
gChemin
(
0
To
27
, 0
To
29
) As
String
' A insérer après le chargement de gTableau
' Charge les données du tableau de retour au centre
With
ThisWorkbook.Sheets
(
"Chemin"
)
For
lCptX =
1
To
28
For
lCptY =
1
To
30
gChemin
(
lCptX -
1
, lCptY -
1
) =
.Cells
(
lCptY, lCptX).Value
Next
Next
End
With
Ensuite on gère les déplacements dans le cas où ReturnToCentre est Vrai.
' Test si le fantôme est sur une case "pleine"
If
Int
(
lFantome.X
) =
lFantome.X
And
Int
(
lFantome.Y
) =
lFantome.Y
Then
' Pas de retour au centre
If
Not
lFantome.ReturnToCentre
Then
' =====> Ici on trouve le code de déplacement précédemment écrit
Else
' Retour au centre
lFantome.Mvt
=
gChemin
(
lFantome.X
, lFantome.Y
)
' Si plus de déplacement => on est arrivé au centre
If
lFantome.Mvt
=
""
Then
lFantome.ReturnToCentre
=
False
End
If
End
If
Et enfin on affiche la paire d'yeux lors du retour au centre.
' Dessine le fantôme et ajoute une région rectangulaire
If
lFantome.ReturnToCentre
Then
oGdi.DrawImg
"yeux"
, lX, lY, , , , _
GdipSizeModeAutoSize, , , CStr
(
ObjPtr
(
lFantome))
Else
oGdi.DrawImg
"ghost"
&
IIf
(
lFantome.Scared
>
0
, "scared"
, lFantome.img
), lX, lY, , , , _
GdipSizeModeAutoSize, , , CStr
(
ObjPtr
(
lFantome))
End
If
On peut alors tester le retour au centre des fantômes :
XV-L. Fin du jeu▲
Il nous reste une dernière chose : tester si les pastilles ont été toutes mangées.
A la fin de la procédure de mise à jour du jeu (ClScreen_UpdateScreen), on teste si le compteur de pastille est à zéro.
Si c'est le cas, on bascule vers l'écran de jeu gagné.
' Test de fin du jeu
If
gNbPastilles =
0
Then
gNextScreen =
"gameend"
gChangeScreen =
True
End
If
Si on mange toutes les pastilles, le jeu se termine.
Prochaines étapes : la création des écrans de fin de jeu :
- écran de jeu perdu ;
- écran de jeu gagné ;
- écran des scores ;
- écran des crédits.