Moteur du punch "retour à Winterfell"

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Moteur du punch "retour à Winterfell"

Message par Huitbit »

Bonjour,

Quelques explications sur la physique qui se cache derrière le petit jeu de bascule "retour à Winterfell"

http://purebasic.fr/french/viewtopic.ph ... &start=240

J'ai utilisé ce qu'on appelle la conservation du moment cinétique.
Pour le vol, la notion de chute libre (voir la macro dans le code)
Par contre, pour modéliser l'impulsion donnée par les jambes du sauteur, il n'y a pas de modèle
alors, j'ai juste multiplié la vitesse de départ du sauteur par un facteur arbitraire.

Dans le punch, j'ai dû définir une vitesse minimale et une vitesse maximale pour éviter les situations anormales
(vMax=racine(2*g*hMax) formule obtenue avec la conservation de l'énergie mécanique).
Il y a environ 70 tests :mrgreen: dans ce punch qui à la base fait 370 lignes (je vous laisse imaginer les cas à tester).


Bref voici le code du moteur :
(tout est proportionnel à la taille de la bascule a=256, il suffit de changer a pour changer les dimensions,
dans le punch a=128.
A correspond au sprite de gauche
B au sprite de droite
On peut modifier mA et mB (dans le punch mA = mB) )

Code : Tout sélectionner

; Simulation de bascule
; Conservation du moment cinétique

; Huitbit juillet 2014
; PureBasic 5.22 
; *********************************
;- déclarations et initialisations des variables
EnableExplicit
;{ 
Enumeration
    #sprBasculeA
    #sprBasculeB
    #sprA
    #sprB
   #volA
   #volB
    #volNull    
  EndEnumeration
  
;- dimensions écran
;{ 
ExamineDesktops()
Define.i L = DesktopWidth(0) * 3 / 4
Define.i H = DesktopHeight(0) * 3 / 4
;} 

#g = 10 ; intensité du champ de pesanteur
#dt = 0.1 ; pas de calcul pour la méthode d'Euler
Define.f dvy = #g * #dt
Define.i dxBascule = 4

Define.f xA, yA, vxA, vyA, vA, yAprecedent
Define.f xB, yB, vxB, vyB, vB, yBprecedent

Define.w vol = #volNull
Define.w sprBascule = #sprBasculeA

Define.i a = 256 ; largeur  du sprite bascule
Define.i b = a / 4 ; hauteur bascule
Define.i lBascule = Sqr(a * a + b * b) ; longueur en pixels de la planche de la bascule(diagonale du rectangle)
Define.i c = a / 8 ; côté personnage
Define.f pente = b / a
Define.f alpha = ATan2(a, b)
Define.f omega = 0 ; vitesse angulaire
Define.i mBascule = 10 ;masses
Define.i mA = 100
Define.i mB = 100
Define.i jbascule = mBascule * lBascule * lBascule / 12 ; J=mL²/12 moment d'inertie de la planche
Define.i jtotal
Define.f rA
Define.f rB
Define.f xBascule = (L - a) / 2
Define.f yBascule = H - b - 5

Define.f yCentreBascule = yBascule + b * 0.5
Define.f xCentreBascule = xBascule + a * 0.5
Define.i i ; variable d'itération
;} 

;- macros
;{ 

Macro chuteLibre(x, y, vx, vy)
    ; vx = vx+0*#dt pas de composante de g selon l'horizontale
    vy = vy + dvy
    x = x + vx * #dt
    y = y + vy * #dt
    
EndMacro

Macro rayon(r, x1, y1, x2, y2)
    r = Sqr((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1))
EndMacro

;} 
;- déclarations des procédures
;{ 
;} 

;-
;-PROGRAMME PRINCIPAL
InitSprite()
InitKeyboard()
OpenWindow(0, 0, 0, L, H, "", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
OpenWindowedScreen(WindowID(0), 0, 0, L, H, 0, 0, 0, #PB_Screen_SmartSynchronization)

;- sprites bascule
;{ 
CreateSprite(#sprBasculeA, a, b) ; A en haut
StartDrawing(SpriteOutput(#sprBasculeA))
    DrawingMode(#PB_2DDrawing_Outlined)
    Box(0, 0, a, b, RGB(255, 255, 0))
    LineXY(0, 0, a, b, RGB(255, 192, 0))
    LineXY(a / 2, 0, a / 2, b, RGB(255, 0, 0))
    For i = 0 To 3 * a / 8
        Box(i,(pente * i), 1, 2, RGB(255, 32, 0))
    Next i
    For i = 5 * a / 8 To a
        Box(i,(pente * i), 1, 2, RGB(255, 32, 0))
    Next i
    
    
StopDrawing()

CreateSprite(#sprBasculeB, a, b) ; B en haut
StartDrawing(SpriteOutput(#sprBasculeB))
    DrawingMode(#PB_2DDrawing_Outlined)
    Box(0, 0, a, b, RGB(255, 255, 0))
    LineXY(0, b, a, 0, RGB(255, 192, 0))
    LineXY(a / 2, 0, a / 2, b, RGB(255, 0, 0))
    
    For i = 0 To 3 * a / 8
        Box(i,(b - pente * i), 1, 1, RGB(255, 0, 0))
    Next i
    
    For i = 5 * a / 8 To a
        Box(i,(b - pente * i), 1, 1, RGB(255, 0, 0))
    Next i
    
    
    
StopDrawing()

;} 
;- sprites personnages A et B
;{ 
CreateSprite(#sprA, c, c)
StartDrawing(SpriteOutput(#sprA))
    DrawingMode(#PB_2DDrawing_Outlined)
    Box(0, 0, c, c, RGB(0, 255, 0))
StopDrawing()

CreateSprite(#sprB, c, c)
StartDrawing(SpriteOutput(#sprB))
    DrawingMode(#PB_2DDrawing_Outlined)
    Box(0, 0, c, c, RGB(0, 0, 255))
StopDrawing()

;} 

;- état initial
xA = xBascule
yA = yBascule - (1 - b / a) * c ; prise en compte de l'inclinaison de la planche


xB = xBascule + a - c
yB = yBascule + b - c

;-
;-BOUCLE PRINCIPALE
Repeat
    ;{ 
    ;- gestion clavier
    ExamineKeyboard()
    If KeyboardPushed(#PB_Key_Left)
        If xBascule > 0
            xBascule = xBascule - dxBascule
            If vol <>#volA
                xA = xA - dxBascule
            EndIf
            If vol <>#volB
                xB = xB - dxBascule
            EndIf
        EndIf
    EndIf
    
    If KeyboardPushed(#PB_Key_Right)
        If xBascule + a < L
            xBascule = xBascule + dxBascule
            If vol <>#volA
                xA = xA + dxBascule
            EndIf
            If vol <>#volB
                xB = xB + dxBascule
            EndIf
            
        EndIf
    EndIf
    
    
    
    If KeyboardPushed(#PB_Key_Space)
        
        ;- Démarrage
        If vol = #volNull
            vol =#volB
            xB = xA + a - c
            yB = yA
            vxB = 0 * Sin(alpha); vxB=0  !
            vyB = -80 * Cos(alpha)
            sprBascule = #sprBasculeB
            ; xA=xA
            yA = yBascule + b - c
        EndIf ; vol=#volNull
    EndIf ; KeyboardPushed(#PB_Key_Space)
    ;} 
    ; mise à jour de la position du centre de la bascule
    xCentreBascule = xBascule + a * 0.5
    
    ;- Animation
    ;{ 
    If vol =#volA
        yAprecedent = yA
        chuteLibre(xA, yA, vxA, vyA)
        If vyA > 0 ; le sprite A redescend
            If (xA >= xBascule) And (xA <= xBascule + 3 * a / 8 - c)
                If (yA + c) >= yBascule And (yAprecedent + c) <= yBascule
                    
                    ; replacement de A au moment du choc en fonction de sa distance par rapport à l'axe
                    yA = yCentreBascule - pente * (xCentreBascule - (xA + c)) - c
                    
                    ; initialisation pour le départ de B
                    vol =#volB
                    
                    ; Calcul de |vB> en appliquant les lois de la mécanique
                    
                    ; calcul des rayons
                    rayon(rA,(xA + c / 2),(yA + c), xCentreBascule, yCentreBascule)
                    rayon(rB,(xB + c / 2),(yB + c), xCentreBascule, yCentreBascule)
                    ; Calcul du moment d'inertie total : Jtotal=mA*rA²+mB*rB²+Jbascule
                    jtotal = mA * rA * rA + mB * rB * rB + jbascule
                    
                                        
                    omega = mA * ((xA + c / 2 - xCentreBascule) * vyA - (yA + c - yCentreBascule) * vxA) / jtotal
                    
                    ; on place B en position haute
                    yB = yCentreBascule - pente * (xB - xCentreBascule) - c
                    vB = Abs(rB * omega * 2.5) ; 2,5 facteur arbitraire qui modélise l'impulsion donnée par le sauteur
                    vxB = -vB * Sin(alpha)
                    vyB = -vB * Cos(alpha)
                    
                    ; replacement de A au moment du départ de B en fonction de sa distance par rapport à l'axe
                    yA = yBascule + b - pente * (xA - xBascule) - c
                    sprBascule = #sprBasculeB
                    
                    
                    
                EndIf ; test sur yA+c=yApiedDroit et la position précedente du pied droit
            EndIf ; test xA
        EndIf ; vyA>0
        If yA > H
            Delay(1000)
            End
        EndIf
    EndIf ; vol=#volPop
    
    
    
    If vol =#volB
        yBprecedent = yB
        chuteLibre(xB, yB, vxB, vyB)
        
        
        If vyB > 0 ; le sprite B redescend
            If (xB >= xBascule + 5 * a / 8) And (xB <= xBascule + a)
                If (yB + c) >= yBascule And (yBprecedent + c) <= yBascule
                    
                    
                    
                    ; replacement de B au moment du choc en fonction de sa distance par rapport à l'axe
                    yB = yCentreBascule - pente * (xB - xCentreBascule) - c
                    
                    
                    ; initialisation pour le départ de A
                    vol =#volA
                    
                    ; Calcul de |vA> en appliquant les lois de la mécanique
                    ; Calcul du moment d'inertie total : Jtotal=mA*rA²+mB*rB²+Jbascule
                    ; calcul des rayons
                    rayon(rA,(xA + c / 2),(yA + c), xCentreBascule, yCentreBascule)
                    rayon(rB,(xB + c / 2),(yB + c), xCentreBascule, yCentreBascule)
                    
                    jtotal = mA * rA * rA + mB * rB * rB + jbascule
                    
                    omega = mB * ((xB + c / 2 - xCentreBascule) * vyB - (yB + c - yCentreBascule) * vxB) / jtotal
                    
                    ; on place A en position haute
                    yA = yBascule + pente * (xA + c - xBascule) - c
                    vA = Abs(rA * omega * 2.5); 2,5 facteur arbitraire qui modélise l'impulsion donnée par le sauteur
                    
                    
                    
                    vxA = vA * Sin(alpha)
                    vyA = -vA * Cos(alpha)
                    
                    
                    ; replacement de B au moment du départ de A en fonction de sa distance par rapport à l'axe
                    yB = yCentreBascule + pente * (xB + c - xCentreBascule) - c
                    
                    sprBascule = #sprBasculeA
                    
                EndIf ; test sur yB+c=yBpiedGauche et la position précedente du pied gauche
            EndIf ; test xB
        EndIf ; vyB>0
        If yB > H
            Delay(1000)
            End
        EndIf
        
    EndIf ; vol=#volAphr
    ;} 
    
    ;- affichage
    ClearScreen(RGB(155, 155, 155))
    
    DisplaySprite(sprBascule, xBascule, yBascule)
    DisplayTransparentSprite(#sprA, xA, yA)
    DisplayTransparentSprite(#sprB, xB, yB)
    
    StartDrawing(ScreenOutput())
        DrawText(0, 0, "xA=" + xA + "   yA=" + yA + "   xB=" + xB + "   yB=" + yB)
        DrawText(0, 20, "vxA=" + vxA + "   vyA=" + vyA + "   vA=" + vA + "   vxB=" + vxB + "   vyB=" + vyB + "   vB=" + vB)
        DrawText(0, 40, "w=" + omega + "   rA=" + rA + "   rB=" + rB)
        DrawText(0, 60, "xBascule=" + xBascule + "   yBascule=" + yBascule + "   xC=" + xCentreBascule + "   yC=" + yCentreBascule)
        
    StopDrawing()
    
    
    FlipBuffers()
    ;} 
Until WindowEvent() = #PB_Event_CloseWindow
End


; @@@@@@@@@@@@@@@@
;- @@@@    INFOS     @@@@
; @@@@@@@@@@@@@@@@

; Conservation du moment cinétique     I*|omega>= |L >
; I moment d'inertie
; omega vitesse angulaire, |v> = |omega> ^|r>
; L moment cinétique  avec |L> = |r> ^|p>
; |r> vecteur correspondant à la distance par rapport à l'axe de rotation (ici coordonnées de A ou de B selon le cas)
; |p> quantité de mouvement |p> = m*|v> avec |v> vecteur vitesse


; (xBascule,yBascule) >>> haut gauche bascule
; (xA,yA) >>>A en haut
; (xA,yBascule+b-c) >>>A en bas
; (xA+a-c,yA) >>>  B en haut
; (xA+a-c,yBascule+b-c) >>>B en bas

Hasta la vista !

PS : pour le punch, j'ai fait des tests avec le code original, j'espère que je n'ai pas laissé traîner des erreurs :oops:
Dernière modification par Huitbit le dim. 31/août/2014 21:55, modifié 2 fois.
Elevé au MSX !
Avatar de l’utilisateur
Cool Dji
Messages : 1126
Inscription : ven. 05/sept./2008 11:42
Localisation : Besançon
Contact :

Re: Moteur du punch "retour à Winterfell"

Message par Cool Dji »

C'est du grand art, merci HuitBit pour le code commenté.
Only PureBasic makes it possible
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Re: Moteur du punch "retour à Winterfell"

Message par Huitbit »

Merci,

Dans la "vrai" version, on retrouvera Popolon, Aphrodite (jeux Konami Knightmare, The Maze of Galious) et leurs animations (ce qui n'était pas trop possible avec le punch :mrgreen: )

Image
A noter le décalage des pieds qui correspond à la ligne rouge dans les carrés
Image

Hasta la vista !
Elevé au MSX !
Avatar de l’utilisateur
MLD
Messages : 1124
Inscription : jeu. 05/févr./2009 17:58
Localisation : Bretagne

Re: Moteur du punch "retour à Winterfell"

Message par MLD »

@ Huitbit
Chapeau :lol:
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: Moteur du punch "retour à Winterfell"

Message par G-Rom »

ma prod préféré , c'est là que l'on voit qu'il y en a entre les 2 oreilles , j'aurais trop aimé avoir un prof comme toi ! :mrgreen:
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Re: Moteur du punch "retour à Winterfell"

Message par Huitbit »

:oops:
Merci, moi, j'aimerais avoir un jour un élève qui ait le dixième de ton potentiel !
Malheureusement, d'année en année, on s'enfonce...et les résultats au bac n'ont jamais été aussi bons :mrgreen:

Hasta la vista !
Elevé au MSX !
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: Moteur du punch "retour à Winterfell"

Message par G-Rom »

Huitbit a écrit ::oops:
Merci, moi, j'aimerais avoir un jour un élève qui ait le dixième de ton potentiel !
Malheureusement, d'année en année, on s'enfonce...et les résultats au bac n'ont jamais été aussi bons :mrgreen:

Hasta la vista !

J'ai la trentaine passée , je me suis "assagi" à tel point que l'on m'appelle le tibetain au boulot ^^ , tu m'aurais eu en tant qu'élève plus jeune, tu m'aurais pendu à un cocotier :mrgreen:
je veut bien tout plaqué pour reprendre mes études en guadeloupe , j'ai aucun diplômes civil :mrgreen:
Répondre