Mouvement d'un dé dans un UserForm

pijaku Messages postés 12263 Date d'inscription jeudi 15 mai 2008 Statut Modérateur Dernière intervention 4 janvier 2024 - Modifié par pijaku le 18/09/2014 à 09:24
pijaku Messages postés 12263 Date d'inscription jeudi 15 mai 2008 Statut Modérateur Dernière intervention 4 janvier 2024 - 10 nov. 2014 à 08:09
Bonjour,

J'essaie de rendre "réaliste" (on s'entend bien, ça n'est que du VBA...), le jet de dé et son déplacement au sein d'un UserForm.

Je me heurte actuellement à deux problèmes :
1- par moment l'userform "bloque". Il reste figé comme lors d'un plantage Excel avec un message d'erreur dans son Caption (Ne répond pas...), puis m'affiche "l'image finale".
Je pense que cela est du aux .Repaint en boucles... A voir.

2- Le dé ne respecte pas l'obstacle que représente le bord bas de l'UserForm. Il "déborde" vers le bas. Je n'ai pas ce souci avec les 3 autres bords (quoiqu'un léger souci avec le bord droit...).
Ce problème est matérialisé, dans le code, par des commentaires :
'///////////////////////SOUCI


Pour vous rendre compte, par vous mêmes, vous pouvez, au choix, télécharger mon fichier exemple : sur cjoint.com, ou faire votre propre fichier.
Dans un cas, comme dans l'autre, vous aurez besoin des images des dés (à renommer : 1.jpg, 2.jpg etc... 6.jpg)


Pour faire votre propre fichier, dans un classeur vierge :
- insérez un UserForm (propriété Name : "Piste")
- dessinez y un contrôle Image (propriété Name : "ImageDe")

Les codes :
Module de l'UserForm :
Option Explicit

Dim StopIt As Boolean

Private Sub UserForm_Initialize()
With Me
    .Height = 700
    .Width = 700
    .BackColor = 32768
    .Caption = "Piste de dés"
    With .ImageDe
        .Height = 24
        .Width = 24
        .Visible = False
    End With
End With
End Sub

'Pour calculer la force de lancer du dé (entre 1 et 100), le joueur doit maintenir le bouton gauche de la souris appuyé
'durant tout le temps ou ce bouton est maintenu (UserForm_MouseDown), la variable Force varie de 1 à 100 et de 100 à 1
'l'arrêt de cette procédure se fait en relachant le bouton (UserForm_MouseUp)
'la variable Boolean StopIt, déclarée en entête de ce module, combinée au DoEvents permet cet arrêt
Private Sub UserForm_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
Dim i As Integer
'initialisation de la variable Force (à chaque clic dans l'UserForm)
Force = 1
StopIt = False
'la variable i prends les valeurs uniques 1 &  -1
'Elle sert donc à faire varier le "sens" d'incrémentation de la variable Force :
'quand i = 1, Force varie de 1 vers 100
'quand i = -1, Force varie de 100 vers 1
Do While StopIt = False
    Force = Force + (1 * i)
    If Force = 1 Then i = 1
    If Force = 100 Then i = -1
    DoEvents 'permet de déclencher l'événement Mouse_Up et donc de Stopper cette boucle
Loop
End Sub
Private Sub UserForm_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
StopIt = True
Jeter_Les_Des
End Sub


Dans un module standard :
Option Explicit

Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Public Force As Integer

Dim De_Left As Integer, De_Top As Integer
Dim Coeff_Sens_Left As Double, Coeff_Sens_Top As Double

Sub Jeter_Les_Des()
Dim Tb(), i As Integer, Chemin As String, Cpt As Integer, Attente As Long

'Initialisation des variables
Chemin = ThisWorkbook.Path & "" '=> Pour les images à afficher dans le contrôle ImageDe
Randomize Timer ' => Tirages aléatoires
Attente = 80 + (100 - Force) ' => Représente la vitesse initiale du dé

Call Mouvements_Du_De(Tb())  ' Calcule et stocke toutes les positions du dés + ses valeurs

For i = LBound(Tb, 2) To UBound(Tb, 2) ' Boucle sur toutes les positions prévues du dé
    'ralenti le dé
    Cpt = Cpt + 1
    If Cpt >= UBound(Tb, 2) / 10 Then
        Cpt = 0
        Attente = Attente + 20
    End If
    'affiche l'image du dé
    With Piste
        With .ImageDe
            .Move Tb(1, i), Tb(2, i), 24, 24
            .Visible = True
            .Picture = LoadPicture(Chemin & Tb(3, i) & ".jpg")
            .PictureSizeMode = fmPictureSizeModeStretch
        End With
        .Repaint
    End With
    Sleep Attente
Next i
End Sub

'Calcule et stocke toutes les positions du dés + ses valeurs
'Les données, stockées dans une variable tableau, sont : Left + Top + Valeur du dé
Sub Mouvements_Du_De(ByRef Tbl())
Dim i As Integer, Valeur_Du_De As Byte, FinBoucle As Integer

'Si la force =  1, il n'y aura pas de mouvement. Le dé tombe sur la piste.
'Dans ce cas, on ne lance que la procédure Point_De_Chute_Du_De.
If Force = 1 Then
    Call Point_De_Chute_Du_De(Tbl())
    Exit Sub
End If

'Point_De_Chute_Du_De => calcule aléatoirement ou va tomber le dé.
Call Point_De_Chute_Du_De(Tbl())
'Sens_Aleatoire => Calcule aléatoirement un coefficient Left et un coefficient Top
'Ces deux coefficients, multipliés à des constantes (en fonction de la force),
'nous donnent les coordonnées des emplacements du dé.
Call Sens_Aleatoire

'Initialisation variable
'La force va diminuer au fur et à mesure de la boucle, on stocke donc sa valeur initiale.
FinBoucle = Force

For i = 2 To FinBoucle
    'calcul des coordonnées de l'emplacement suivant, en fonction de l'emplacement actuel.
    De_Left = Tbl(1, i - 1) + (Force * 1.5) * Coeff_Sens_Left
    De_Top = Tbl(2, i - 1) + (Force * 1.5) * Coeff_Sens_Top
    
    '******************************************************************************************* A Faire.
    
    'Apporter un coeff supplémentaire à une des deux "directions" pour donner un effet moins linéaire aux déplacements
    
    '*******************************************************************************************
    
    'Permet de changer de sens lorsque le dé touche un des bords de la piste
    If De_Left < 0 Then
        Coeff_Sens_Left = Coeff_Sens_Left * -1
        De_Left = 0
    End If
    'Pas de valeur numérique => permet de changer la taille de l'UserForm
    If De_Left >= Piste.Width - Piste.ImageDe.Width Then
        Coeff_Sens_Left = Coeff_Sens_Left * -1
        De_Left = Piste.Width - Piste.ImageDe.Width '///////////////////////SOUCI "Léger"
    End If
    If De_Top < 0 Then
        Coeff_Sens_Top = Coeff_Sens_Top * -1
        De_Top = 0
    End If
    If De_Top >= Piste.Height - Piste.ImageDe.Height Then
        Coeff_Sens_Top = Coeff_Sens_Top * -1
        De_Top = Piste.Height - Piste.ImageDe.Height '///////////////////////SOUCI "Important"
    End If
    
    '*******************************************************************************************A modifier.
    'En fin de mouvement du dé, le dé roule et donc un 4 (par ex) ne peut pas être suivi :
        '- ni pas un 4 (dé glissé),
        '- ni par un 3 (situé sur l'autre face)
    Valeur_Du_De = CInt((5 * Rnd()) + 1)
    '*******************************************************************************************
    
    'stockage des valeurs
    ReDim Preserve Tbl(1 To 3, 1 To i)
    Tbl(1, i) = De_Left
    Tbl(2, i) = De_Top
    Tbl(3, i) = Valeur_Du_De
    'Baisse de la force => le dé va de moins en moins loin par rapport à sa position actuelle
    Force = CInt(Force - (Force / 20))
Next i
End Sub

Sub Point_De_Chute_Du_De(ByRef Tabl())
'calcul aléatoire des 3 valeurs initiales du dé
Erase Tabl
ReDim Preserve Tabl(1 To 3, 1 To 1)
Tabl(1, 1) = CInt((675 * Rnd()) + 1) ' => Propriété Left
Tabl(2, 1) = CInt((675 * Rnd()) + 1) ' => Propriété Top
Tabl(3, 1) = CInt((5 * Rnd()) + 1) ' => Valeur
End Sub

Sub Sens_Aleatoire()
'calcul aléatoire de Coeff_Sens_Left et Coeff_Sens_Top pour la première direction
Dim Valeurs(200), i As Long

'Les 2 coeffs sont des valeurs comprises entre -1 et +1 Step 0.01 : -1, -0.99, -0.98, ...
For i = -100 To 100
    Valeurs(i + 100) = i / 100
Next i
'calcul aléatoire de Coeff_Sens_Left et Coeff_Sens_Top
Coeff_Sens_Left = Valeurs(CInt((199 * Rnd()) + 1))
Coeff_Sens_Top = Valeurs(CInt((199 * Rnd()) + 1))
End Sub


Merci de m'avoir lu jusqu'ici et pour vos éventuels éclaircissements.

Cordialement,
Franck

23 réponses

ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
3 oct. 2014 à 10:58
C'est plus complexe que cela, notamment dans le cas 1.
Le dé heurté ne peut continuer dans la même direction que s'il est heurté exactement à l'arrière par un dé allant exactement dans la même direction
Quelque soit d'ailleurs le cas de figure : deux paramètres entrent systématiquement en oeuvre :
1) un paramètre cinétique (la vitesse de chaque dé)
2) un paramètre dynamique, nécessairement dépendant en plus du poids des dés. Il y a dans tous les cas un calcul du vecteur résultant pour chaque dé.
C'est complexe.
0
pijaku Messages postés 12263 Date d'inscription jeudi 15 mai 2008 Statut Modérateur Dernière intervention 4 janvier 2024 14
3 oct. 2014 à 11:03
Il y a dans tous les cas un calcul du vecteur résultant pour chaque dé.
C'est ce que j'essaye de réaliser.

Par contre, en fonction de la vitesse ok, cela me semble faisable. Mais en fonction du poids?
Ne peut-on pas ignorer ce facteur poids sous prétexte que les dés sont identiques?
Sinon, effectivement cela semble hyper compliqué à mettre en place et, là, le jeu n'en vaut pas la chandelle...
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
Modifié par ucfoutu le 3/10/2014 à 11:19
Que les dés soient ou non identiques, ils ont un poids et ce poids intervient, comme la vitesse, dans le calcul.
On devrait d'ailleurs parler là de puissance, d'énergie, ...
je vais chercher un lien en parlant

________________________
Réponse exacte ? => "REPONSE ACCEPTEE" facilitera les recherches.
Pas d'aide en ligne installée ? => ne comptez pas sur moi pour simplement répéter son contenu. Je n'interviend
0
ucfoutu Messages postés 18038 Date d'inscription lundi 7 décembre 2009 Statut Modérateur Dernière intervention 11 avril 2018 211
3 oct. 2014 à 11:20
0
pijaku Messages postés 12263 Date d'inscription jeudi 15 mai 2008 Statut Modérateur Dernière intervention 4 janvier 2024 14
3 oct. 2014 à 12:12
Oui...
Mais...
Je l'aime bien ce "mais".
Si on se base sur ces deux équations (approximation du choc entre deux boules de billard) :

ou m1 et m2 sont les masses respectives des boules, u les vitesses avant et v les vitesses après choc.
Si m1 = m2, on peut supprimer le poids de l'équation.
u1 + u2 = v1 + v2
-v + u = v - u
Donc, deux objets qui se choquent, ayant la même masse, repartent chacun avec leur vitesse initiale, si l'on considère le "coefficient de restitution" comme négligeable. On peut, nous, dans notre cas bien précis, si on le désire, définir un coefficient de restitution sous la forme d'une constante que l'on approximera pour obtenir un objectif purement "visuel".
Ceci est donc ok en ce qui concerne la vitesse.

Maintenant, si l'on s'attache à l'angle, il faut considérer le côté subissant l'impact comme étant un plan rigide. Les deux dés repartent alors avec un angle de réflexion égale à l'angle d'incidence. Un peu comme sur ce schéma :
0
pijaku Messages postés 12263 Date d'inscription jeudi 15 mai 2008 Statut Modérateur Dernière intervention 4 janvier 2024 14
3 oct. 2014 à 13:25
J'en arrive donc à ceci :
                
'Cas 1 : Les dés vont dans la même direction ou presque
'=> le dé heurté :
'accélère légèrement ("coefficient de restitution"),
'change de direction mais pas de sens
'Angle?????
'=> le dé qui heurte :
'ralentit ("coefficient de restitution"),
'change de direction et de sens suivant l'angle de réflexion (= angle d'incidence)

'Cas 2 : les dés vont dans des directions opposées
'=> les deux dés
'ralentissent ("coefficient de restitution")
'changent de sens suivant l'angle de réflexion (= angle d'incidence)


Il me reste à comprendre le calcul de l'angle du dé heurté dans le cas 1.
Mais présentement, je ressens les effets d'une "sur-méningite" aiguë et j'ai un violent besoin de paracétamol. Donc, si vous le voulez bien, je vais arrêter pour l'instant et laisser passer le temps de la réflexion (ah non encore un terme en rapport avec les angles!).
Je reviendrais lire vos commentaires, n'ayez crainte...
0
pijaku Messages postés 12263 Date d'inscription jeudi 15 mai 2008 Statut Modérateur Dernière intervention 4 janvier 2024 14
6 oct. 2014 à 09:30
Bonjour,

Les nuits blanches du week end (merci Théo) portant conseil, il s'avère que l'on ne doit traiter le choc entre les dés qu'avec tous les paramètres nécessaires. Autrement dit, la vitesse, l'angle, la direction et la masse des dés sont des paramètres qui se doivent d'être pris en compte.
Par contre, je ne prendrais pas en compte la force du frottement de la piste ni l'effet du au "roulis" des dés.
Donc...
Il me faut me replonger dans mes manuels de physique du lycée et établir les formules utiles dans le calcul des angles et des vitesses de chaque dé après choc pour chacun des cas pouvant se produire.
Je reviendrais dès que j'aurais mis au point tout cela, c'est plus complexe que prévu, mais cette étude m'intéresse et pourra servir à d'autres... ou pas.

Je vous dit donc à très bientôt.
0
pijaku Messages postés 12263 Date d'inscription jeudi 15 mai 2008 Statut Modérateur Dernière intervention 4 janvier 2024 14
10 nov. 2014 à 08:09
Bonjour,

Non je n'ai pas laissé tomber, c'était juste plus complexe que prévu.
J'ai tout de même réussi à obtenir les formules nécessaires pour continuer ce projet. Toutefois, il faut savoir que pour un cas, il faudra définir un paramètre de sortie arbitrairement (3 équations à 4 inconnues).
Si vous êtes intéressés par ces formules et leurs "démonstrations", je me ferais une joie de vous les transmettre.
Dans le cas contraire, je reviendrais ici afin de vous faire part de l'avancée du code et des éventuelles difficultés que je rencontrerai assurément...
0
Rejoignez-nous