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 Sub

Le 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 Sub

Et 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 Sub

C'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 Double

Et 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 Sub

Avec 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 Boolean

Et 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 ! Ceci dit ce nouveau projet en est un qui je l'espère sera plus "fluide" que les deux autres.
Vous pouvez regardez ici ou 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

Rechercher des sujets similaires à "type personnalise dictionary"