Type personnalisé dans un Dictionary
Bonsoir,
avec mon application ArkaLouReeD Light !, je gère des shapes pour lesquels j'ai créé des type personnalisé.
Par exemple pour les balles, dont un bonus peut faire qu'il y en a 20 par exemples, j'ai un type personnalisé qui me permet de gérer leur position en left et en top, ainsi que leur angles et vitesse de déplacement. Une fois le type créé, je dimensionne un tableau Balle(1 to 20) As Type_Balle afin de pouvoir boucler sur les balles et les déplacer une par une à chaque tour de la boucle de jeu.
cela donne un code comme ceci :
' on crée un type personnalisé
Type Balle_Type
O As Shape ' le shape de la balle
A As Double ' l'angle
V As Double ' la vitesse
Tx As Double ' la translation en X de la balle
Ty As Double ' la translation en Y de la balle
End Type
' on dimensionne un tableau de ce type avec par exemple 20 index pour gérer jusqu'à 20 balles
Public Balle(1 To 20) As Balle_Type
Sub Jeu
For I=1 to 20
If Balle(I].O.Visible = True then ' si le shape de la balle en question est visible alors
Balle(I).O.Left = Balle(I).O.Left + Balle(I).Tx
Balle(I).O.Top = Balle(I).O.Top + Balle(I).Ty
End If
Next I
End SubLe code est très simplifié !
Mais on voit un test de visibilité du shape afin de savoir s'il est en jeu ou perdu. En effet, même s'il n'y a que trois balles en jeu, cela ne veut pas dire que ce sont les balles des trois premier index du tableau des balles ! Si le bonus 20 balles est sorti, alors à la perte de plusieurs balles le tableau contient des "trous" si on peut dire.
C'est pour cela que j'avais imaginé un code de réorganisation de ce tableau afin de remettre les balles "en jeu" au début de ce de celui-ci :
Sub BalleOrganisation()
Dim Bcl As Integer
' on commence avec la balle 1
Bcl = 1
Do
' si la balle est masquée alors elle est perdue
If Balle(Bcl).O.Visible = False Then
' avec cette balle perdue on récupère les données de la dernières du tableau
With Balle(Bcl)
.O.Name = "Bal_" & Format(Bcl, "00")
.Tx = Balle(NbBallesEnJeu).Tx
.Ty = Balle(NbBallesEnJeu).Ty
.O.Top = Balle(NbBallesEnJeu).O.Top
.O.Left = Balle(NbBallesEnJeu).O.Left
' on la remet visible
.O.Visible = True
' la dernière balle du tableau passe invisible
Balle(NbBallesEnJeu).O.Visible = False
' le nombre de balle en jeu diminue de 1
NbBallesEnJeu = NbBallesEnJeu - 1
' on décrémente le nombre de balle perdue
BallePerdue = BallePerdue - 1
End With
End If
' on passe à la balle suivante
Bcl = Bcl + 1
' on tourne tant qu'il reste des balles perdues à trouver
Loop While BallePerdue > 0
End SubEt encore ce code n'est pas "optimisé" dans le sens où je ne teste pas si la dernière balle du tableau est bien en jeu !
D'où mon idée de remplacer ce tableau "ordinaire" par un dictionary ! Comme cela lorsqu'une balle est perdue il suffit de la supprimer du dictionnaire !
Ceci à donc donné ce code :
' on crée un type personnalisé
Type Balle_Type
O As Shape
T As Double
L As Double
End Type
' on dimensionne un tableau de ce type
Public Balle(1 To 20) As Balle_Type
Sub Test()
' on crée un dictionary
Set Dict = CreateObject("scripting.dictionary")
' avec la feuille 1
With Sheets("Feuil1")
' on rempli le tableau du type personnalisé avec les éléments
For i = 1 To 20
' on attribue le shape
Set Balle(i).O = .Shapes("Image" & i)
' on attribue sa position
With Balle(i)
.T = .O.Top
.L = .O.Left
End With
Next i
' on ajoute ce tableau de type au dictionnaire
Dict.Add "Balles", Balle
End With
End SubC'est une solution simpliste d'essai d'intégration et... et cela provoque une erreur.
Après recherches et un coup de main de Klin89 je suis arrivé au bout de ce projet.
L'astuce est de remplacer la définition du Type personnalisé par un module de classe !
On crée un module de classe portant le nom suivant (par exemple) : BalleType
et on inscrit les variables en Public, chacune correspondant aux différentes données de l'ancien type :
' Dans un module de classe de nom Balle_Type
Public O As Shape
Public T As Double
Public L As DoubleEt la boucle de remplissage du dictionnaire :
Sub Test()
Dim UneBalle as BalleType
' on crée un dictionary
Set Dict = CreateObject("scripting.dictionary")
' avec la feuille 1
With Sheets("Feuil1")
' on rempli le tableau du type personnalisé avec les éléments
For i = 1 To 20
' on attribue le shape
Set UneBalle = New BalleType
Set UneBalle.O = .Shapes("Image" & i)
' on attribue sa position
With UneBalle
.O.Name = "Balle_" & Format(i,"00")
.T = .O.Top
.L = .O.Left
' on ajoute cette balle au dictionnaire
Dict.Add .O.Name, UneBalle
End With
Next i
End With
End SubAvec cette boucle on inscrit 20 balles de type BalleType dans le dictionnaire. Si une balle est perdue il suffit de la retirer du dictionnaire, les boucles du code ne boucleront plus dessus.
Pour connaitre le nombre de balle en jeu : Dict.Count
Pour boucler sur les balle du dictionnaire pour les déplacer par exemple : For Each UneBalle In Dict
Pour accéder aux différentes variables du TypeBalle : Dict(UneBalle).O pour le shape et Dict(UneBalle).L pour le Left
Pour une balle perdue : on supprime le shape : Dict(UneBalle).O.Delete, on la retire du tableau : Dict.Remove UneBalle
Et voilà, j'ai bien un tableau ne comportant que les balles existantes tout en gardant la simplicité d'un format de Type.
si je dois ajouter un paramètre à mes balles, par exemple si elles sont explosives, alors il me suffit d'aller dans le module de classe et d'ajouter un truc du genre :
Public E As BooleanEt je peux facilement ajouter un test dans la boucle par If Dict(UneBalle).E Then
Je travail actuellement sur un nouveau casse brique qui emporte déjà cette technique pour plusieurs objets :
les balles (jusqu'à 32 simultanément !), les capsules bonus (il peu y en avoir 20 !), les bulles de savon (c'est un résultat d'un bonus avec jusqu'à 25 bulles), les lasers (il peu également y en avoir beaucoup !), les monstres (normalement il n'y en a que trois mais à voir suite à la simplification de gestion...)
On verra ce que cela va donner ! Déjà il y a plusieurs différence avec ArkaLouReeD Light !
Le tableau de brique a une dimension de 25 colonnes sur 25 lignes, ce qui fait qu'il y a maintenant des bonus qui permettent de renverser le tableau de haut en bas, de gauche à droite et en rotation de 90° !
il y a des briques explosives : elles détruisent les briques qui les entourent !
Bref quelques nouveautés. le développement est long du fait des différents tests de code pour optimiser tout ceci afin d'améliorer l'expérience de jeu.
@ bientôt
LouReeD
Salut LooReeD,
C'est un très bon exemple d'utilisation des classes pour simplifier ton code. Dans la même veine tu pourrais ensuite ajouter par exemple une méthode Move(dx, dy) à ta classe, qui permet de déplacer la balle de l'incrément indiqué.
L'intérêt c'est que ta boucle appellante devient toujours "plus simple" (on lit "avec ma balle i, je me déplace de dx,dy").
Le deuxième intérêt c'est que dans cette méthode Move tu vas pouvoir implémenter une logique de déplacement plus complexe que "x+dx, y+dy", par exemple vérifier que tu es encore dans les limites du tableau, ou même faire des collisions/rebonds.
Par contre si tu stockes juste tes balles dans une liste, je pense que la Collection ferait aussi l'affaire. L'avantage c'est que c'est compatible MacOS.
Bonne continuation sur ton projet !
Bonjour,
merci pour ce retour !
Vous pouvez regardez ici ou là ce que cela donne ne serait-ce qu'avec le système Type personnalisé et tableau.
C'est déjà pas mal car il a fallu que je mette un curseur "vitesse" pour ralentir les calculs pour que cela soit jouable sur les machines actuelles !
Il est bien évident qu'ici sur ce fil, j'ai simplifié les codes afin de mettre en lumière l'idée qui à mon sens manquait de visibilité sur le net (marrant ça ! Manque de visibilité et le Net !
@ bientôt
LouReeD