# Sources PureBasicConsultez toutes les sources

Nombre d'auteurs : 41, nombre de sources : 88, dernière mise à jour : 13 août 2011

Sommaire→Physique

- Collision et physique (pendule)
- Solide glissant sur un rail soumis à la pesanteur
- Solide glissant sur un rail (avec décollage et chute)

Version hors-ligne
Collision et physique (pendule)

J'utilise la notation "bra ket" (voir mécanique quantique) pour représenter les vecteurs ! Le vecteur AB se note |AB>.
On travaille dans un repère (O,x,y,z) d'axes Ox, Oy et Oz avec les vecteurs associés |i>, |j>, |k> .
Allez jeter un coup d'oeil sur wikipédia si les notions de dérivée, vecteur, projection, produit scalaire, produit vectoriel ( exemples : moment d'une force |M> = |r> ^ |F>, moment cinétique |L> = |r> ^ |p>), moment d'inertie J, moment cinétique |L>, vous sont complètement inconnues !
Les explications suivent les différentes étapes de l'animation.
Modèle du système pseudo-isolé :
La somme des forces (le poids |P> et la réaction du sol |R>) qui s'exercent sur la boule (le système) se compensent.
1ère loi de Newton
Si |P> + |R> = |0> => la boule se déplace à vitesse constante (|v> = |constant>=|v0> vecteur vitesse initial)
or |v> = d|OG>/dt
Avec |OG> vecteur position (G centre de gravité de la boule et O, origine du repère).
Si on projette selon les axes Ox et Oy du repère on a :
vx = v0x = dx / dt
vy = v0y = dy / dt
Approximation d'Euler (on transforme la dérivée en une variation)
dx = v0x * dt
dy = v0y * dt
=> x = x + v0x * dt
=> y = y + v0y * dt
Voilà pour la position de la boule1 dans cette phase.
Modèle de la chute libre :
Il n'y a plus de sol => plus de réaction du sol => les forces ne se compensent plus
2ème loi de Newton
|P> = m * |a> avec m masse de la boule et |a> accélération de la boule.
Or |P> = m * |g> avec |g> champ de pesanteur
=> |a> = |g>
or |a> = d|v>/dt et |v> = d|OG>/dt
On projette puis on applique la méthode d'Euler:
vx = vx + gx * dt = vx
vy = vy + gy*dt = vy+g * dt
Car gx = 0 et gy = g (vecteur vertical, vers le bas comme l'axe des y)
x = x + vx * dt
y = y + vy * dt
Collision boule1-boule2
Modèle utilisé : conservation du moment cinétique lors du choc
On appelle G1 et G2 les centres de gravité des boules.
J le moment d'inertie du système après le choc (boule1 et boule2 collées)
Ici J = J(boule1) + J(boule2) + (prise en compte de la distance qui sépare G1 de G2 avec le théorème de Huygens)
(Dans le code, j'ai pris le J d'un cylindre, c'est à dire 0.5*masse*rayon²)
Selon la situation, on peut exprimer le moment cinétique total de différentes manières :
Avant le choc m1 * |G2G1> ^ |v1> (la boule2 est immobile)
Après le choc J * w * |k> avec w vitesse angulaire du nouveau système, |k> vecteur unitaire de l'axe Oz.
A noter w = da / dt avec a, angle de rotation du nouveau système.
On a donc m1 * |G2G1> ^ |v1> = J * w * |k>
=> w * |k> = m1 * |G2G1> ^ |v1> / J
w = m1 * [(x1 ? x2) * vy1 ? (y1 ? y2)*vx1] / J
Cette valeur de w fixera l'état initial du pendule pesant.
Remarque : pour des raisons esthétiques, je replace systématiquement la boule1 à la bonne distance après le choc !
Pour cela je calcule l'angle que fait le rayon |G1G2> avec le vecteur unitaire de l'axe des x (attention au signe avec l'arctangente !)

Sélectionnez

        If x1c>x2c
          angle1=ATan((y1c-y2c)/(x1c-x2c))
        Else
          angle1=ATan((y1c-y2c)/(x1c-x2c))+#PI
        EndIf
        x1c=x2c+(#r_1+#r_2)*Cos(angle1)
        y1c=y2c+(#r_1+#r_2)*Sin(angle1)

Modèle du pendule pesant :
Principe fondamental de la dynamique pour les solides en rotation
« La somme des moments des forces est égale à la dérivée du moment cinétique »
Ici, la seule force qui ait un moment est le poids |P> (on néglige les forces de frottements depuis le début !)
On a donc :
|GG2 > ^ |P> = J * dw/dt * |k> avec G centre de gravité du nouveau système
|GG2 > ^ (m1+m2) * |g> = J * dw/dt * |k>
Rappel : G est tel que m1 * |GG1> + m2 * |GG2> = |0>
Ce qui donne |GG2> = m1 * |G1G2> / (m1 +m2)
Si on remplace on a
m1 * |G1G2> ^ |g> = J * dw/dt * |k>
m1 * (x2-x1) * g * |k> = J * dw/dt * |k>
dw/dt = m1 * (x2-x1) * g / J
On applique la méthode d'Euler :
w = w + m1 * (x2-x1) * g / J * dt
de même pour l'angle de rotation a = a +w * dt
Et voilà !
On a la variation de l'angle du pendule au cours du temps !
Remarques :
-n'hésitez pas à demander un complément d'informations
-dans le code, dt = 1 cela veut dire que l'on peut remplacer "x = x + v0x * dt" par "x = x +v0x". Je laisse cependant le "dt" car additionner une position avec une vitesse en physique, C'EST MAL
-pour les frottements, il n'y a pas grand chose à rajouter, on verra ça dans un autre épisode !

Sélectionnez

    ;collision_2
    ;auteur Huitbit
    ;pb v4.20
    ;*********************************
    Enumeration
      #spr_decor
      #spr_1
      #spr_2
      #systeme_isole
      #chute_libre
      #pendule_pesant
    EndEnumeration

    #largeur_ecran=1024
    #hauteur_ecran=768

    #g=0.5
    #dt=1

    ;boule n°1
    #r_1=32
    #m_1=1
    x_1.f =0: y_1.f=128-2*#r_1
    x_1_centre.f=x_1+#r_1 : y_1_centre.f=y_1+#r_1
    vx_1.f=2+Random(16): vy_1.f=0

    ;boule n°2
    #r_2=128
    #m_2=4
    x_2.f=512 : y_2.f=256
    x_2_centre.f=x_2+#r_2 : y_2_centre.f=y_2+#r_2
    vx_2.f=-2 : vy_2.f=2

    #d_carre=(#r_1+#r_2)*(#r_1+#r_2)
    #J=0.5*#m_1*#r_1*#r_1+#m_1*#d_carre+0.5*#m_2*#r_2*#r_2
    omega.f

    test.s=""
    contact.b=0
    modele.b
    nom_modele.s
    temps_d_arret.w
    angle1.f
    angle2.f

    Macro test_variation_distance(x1c,y1c,vx1,vy1,x2c,y2c,vx2,vy2)
    If (x1c-x2c)*(vx1-vx2)+(y1c-y2c)*(vy1-vy2)<0
      test="Rapprochement"
    Else
      test="Eloignement"
    EndIf
    EndMacro

    Macro test_contact(x1c,y1c,vx1,vy1,x2c,y2c,vx2,vy2)
    If (x1c-x2c)*(x1c-x2c)+(y1c-y2c)*(y1c-y2c)<=#d_carre+1  And test="Rapprochement"
      contact=1
      If modele=#chute_libre
        If x1c>x2c
          angle1=ATan((y1c-y2c)/(x1c-x2c))
        Else
          angle1=ATan((y1c-y2c)/(x1c-x2c))+#PI
        EndIf
        x1c=x2c+(#r_1+#r_2)*Cos(angle1)
        y1c=y2c+(#r_1+#r_2)*Sin(angle1)
        omega=#m_1/#J*((x1c-x2c)*vy1-(y1c-y2c)*vx1)
      EndIf
      temps_d_arret=temps_d_arret+1
      If temps_d_arret>300
        contact=0
        x1c=#r_1 : y1c=128-#r_1
        vx1=2+Random(16): vy1=0
        angle1=0
        angle2=0
        omega=0
        temps_d_arret=0
      EndIf

    EndIf
    EndMacro

    Macro test_bord_ecran(xc,yc,vx,vy,r)
    If modele=#chute_libre
      If xc+r>#largeur_ecran Or xc<128+r
        vx=-vx
      EndIf
      If yc+r>#hauteur_ecran-32 Or yc<r
        vy=-vy
      EndIf
    EndIf
    EndMacro

    Macro choix_modele
    If x_1_centre<128+#r_1
      modele=#systeme_isole
      nom_modele="système isolé"
    Else
      If contact=0
        modele=#chute_libre
        nom_modele="chute libre"
      Else
        modele=#pendule_pesant
        nom_modele="pendule pesant"
      EndIf
    EndIf
    EndMacro

    InitSprite()
    InitSprite3D()
    InitKeyboard()
    OpenWindow(0,0,0,#largeur_ecran,#hauteur_ecran,"Collision_2D",#PB_Window_ScreenCentered|#PB_Window_SystemMenu  )
    OpenWindowedScreen(WindowID(0),0,0,#largeur_ecran,#hauteur_ecran,0,0,0)

    CreateSprite(#spr_decor, #largeur_ecran,#hauteur_ecran)
    StartDrawing(SpriteOutput(#spr_decor))
    LineXY(0,128,128,128,RGB(0,0,255))
    LineXY(128,128,128,736,RGB(0,0,255))
    LineXY(128,736,1024,736,RGB(0,0,255))
    StopDrawing()

    CreateSprite(#spr_1,#r_1*2,#r_1*2)
    StartDrawing(SpriteOutput(#spr_1))
    DrawingMode(#PB_2DDrawing_Outlined)
    Circle(#r_1,#r_1,#r_1,RGB(255,0,0))
    Plot(#r_1,#r_1,RGB(255,255,255))
    StopDrawing()

    CreateSprite(#spr_2,#r_2*2,#r_2*2,#PB_Sprite_Texture)
    StartDrawing(SpriteOutput(#spr_2))
    DrawingMode(#PB_2DDrawing_Outlined)
    Circle(#r_2,#r_2,#r_2,RGB(0,255,0))
    Line(#r_2,#r_2,#r_2,0,RGB(255,255,255))
    StopDrawing()
    CreateSprite3D(#spr_2,#spr_2)

    Repeat

      Repeat
        Event = WindowEvent()
        If  Event = #PB_Event_CloseWindow
          End
        EndIf
      Until Event = 0

      choix_modele

      If modele=#systeme_isole
        x_1_centre=x_1_centre+vx_1*#dt
      EndIf

      If modele=#chute_libre
        vy_1=vy_1+#g*#dt
        x_1_centre=x_1_centre+vx_1*#dt
        y_1_centre=y_1_centre+vy_1*#dt
      EndIf

      If modele=#pendule_pesant
        omega=omega+#m_1/#J*(x_1_centre-x_2_centre)*#g*#dt
        angle1=angle1+omega*#dt
        x_1_centre=x_2_centre+(#r_1+#r_2)*Cos(angle1)
        y_1_centre=y_2_centre+(#r_1+#r_2)*Sin(angle1)

      EndIf

      test_variation_distance(x_1_centre,y_1_centre,vx_1,vy_1,x_2_centre,y_2_centre,vx_2,vy_2)
      test_contact(x_1_centre,y_1_centre,vx_1,vy_1,x_2_centre,y_2_centre,vx_2,vy_2)
      test_bord_ecran(x_1_centre,y_1_centre,vx_1,vy_1,#r_1)
      test_bord_ecran(x_2_centre,y_2_centre,vx_2,vy_2,#r_2)

      DisplaySprite(#spr_decor,0,0)
      DisplayTransparentSprite(#spr_1,x_1_centre-#r_1,y_1_centre-#r_1)
      Start3D()
      angle2=angle2+omega
      RotateSprite3D(#spr_2,angle2*180/#PI,0)
      DisplaySprite3D(#spr_2,x_2_centre-#r_2,y_2_centre-#r_2)
      Stop3D()
      StartDrawing(ScreenOutput())
      DrawText(0,20,"Modèle : "+nom_modele)
      StopDrawing()

      Delay(1)
      FlipBuffers()
    ForEver

Créé le 18 juillet 2008 par Huitbit
Solide glissant sur un rail soumis à la pesanteur

Petite récréation(première partie) basée sur l'article :
http://www.myphysicslab.com/RollerSimple.html
Ce que l'on vous cache dans cet article !
Ce problème correspond à celui du solide glissant sur un plan incliné.
La difficulté, c'est que l'on considère qu'une courbe est une succession de plans inclinés microscopiques. On regarde donc ce qui se passe sur de très petites portions de la courbe.
C'est une application de la 2ème loi de Newton dans un repère particulier : le repère de Frenet.
m * |a> = |P> + |R>
Avec |P> vecteur poids, vertical vers le bas, |R> vecteur réaction, normal à la courbe.
Dans la base de Frenet, on montre, que l'accélération s'exprime de la manière suivante :
m * |a> = dv/dt * |et> + v²/r * |en>
Avec :
- |et> vecteur tangent à la trajectoire
- |en> vecteur normal à la trajectoire tourné vers la concavité de la trajectoire
- v valeur de la vitesse
- r rayon de courbure de la trajectoire
On a donc
m * (dv/dt * |et> + v²/r * |en>)= dv/dt * |et> + v²/r * |en>
Si on projette on a :
selon la tangente
m * dv/dt = mg * cos(a)
Remarque : si on veut rajouter des frottements, il suffit de rajouter "- coeff_frott * v" dans le terme de droite)
Par exemple, dans le code suivant, remplacez :

Sélectionnez

    ;-équations du mouvement
    vs=vs+#g*courbe(t)\cosinus*#dt

par :

Sélectionnez

    vs=vs+(#g*courbe(t)\cosinus-0.003*vs)*#dt

selon la normale
m * v²/r = m * g * sin(a) ? R
Seule la première équation nous renseigne sur la variation de la vitesse.
La deuxième équation nous sera utile (à suivre dans le prochain message !) pour savoir si le solide reste en contact avec le sol.
En effet, si R = 0 (c'est à dire m * v²/r = m * g * sin(a) -0 ou bien v²/r = * g * sin(a)), le solide quitte le sol.
(voir http://www.myphysicslab.com/RollerFlight.html)
Voilà pour la physique ! Razz
La difficulté maintenant, va être de passer de l'abscisse curviligne s (position sur la courbe) aux coordonnées cartésiennes x,y !
J'ai pris la première méthode qui allait bien, alors n'hésitez pas à trouver mieux !
Pour la courbe, j'ai travaillé avec des équations paramétriques, mais on peut très bien faire avec des « data ». L'intérêt des équations, c'est que l'on peut obtenir facilement leurs dérivées. Avec des « data » on pourra les calculer sans problème de manière approchée avec df(t)/dt ~ (f(t2)-f(t1))/(t2-t1)
Les courbes utilisées sont des gaussiennes (courbes en forme de cloche)
J'ai rajouté la rotation de l'objet en fonction de la pente de la courbe.
Pour placer l'objet sur la courbe (et non enfilé), on peut tricher et calculer à l'avance la courbe qui correspond au coin gauche du sprite.
Pour rajouter un décor, il suffit de construire son décor par rapport à la courbe !

Sélectionnez

    ;solide guidé soumis à la pesanteur
    ;auteur Huitbit
    ;pb v4.20
    ;*********************************
    ;-déclarations de variables
    #largeur_ecran=1024
    #hauteur_ecran=768
    #g=9.8 ;intensité de la pesanteur
    #dt=0.2 ;pas de calcul pour la méthode d'Euler
    Enumeration
      #spr_piste
      #spr_carre_droite
      #spr_carre_gauche
    EndEnumeration
    Structure donnees
      x.f ; x(t)
      y.f ; y(t)
      dx.f
      dy.f
      s.f ; abscisse curviligne s(t)
      cosinus.f; cosinus de l'angle vecteur poids |P> et le vecteur tangent à la courbe
    EndStructure

    s.f ; abscisse curviligne s(t)
    int_s.w; valeur entière de s(t)
    vs.f ; vitesse curviligne
    angle_rotation.w
    spr_carre.b

    ;infos sur les courbes
    t.w ;paramètre pour les fonctions x(t), y(t) et s(t) sur tout le parcours
    t_max.w ; dernière valeur de t
    p.w ; paramètre provisoire pour chaque portion de courbes
    longueur_courbe.f = 0
    #y_depart=92
    e.f=2.718281828 ; valeur de exp(1)
    #parametre_gaussienne_1=0.00003
    #parametre_gaussienne_2=0.0004
    ; point de la courbe pour tracer le premier segment
    x_point_precedent.f=0
    y_point_precedent.f=#y_depart

    ;-tracé de la courbe
    Dim  courbe.donnees(5000)

    t=0
    p=0

    ;première demi-gaussienne
    While courbe(t)\x<#largeur_ecran/2
      t=t+1
      p=p+1
      courbe(t)\x=p
      courbe(t)\y=#y_depart+#hauteur_ecran*0.7*(1-Pow(e,-#parametre_gaussienne_1*p*p))
      courbe(t)\dx=1
      courbe(t)\dy=#hauteur_ecran*0.7*2*#parametre_gaussienne_1*p*Pow(e,-#parametre_gaussienne_1*p*p)
      longueur_courbe=longueur_courbe+Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\s=longueur_courbe
      courbe(t)\cosinus=courbe(t)\dy / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy) ;cosinus de l'angle entre la verticale(direction du poids) et la courbe
    Wend
    t_max=t

    ;ellipse n°1
    For angle=0 To 360
      t=t+1
      courbe(t)\x=courbe(t_max)\x+150*Cos(#PI*(-angle+90)/180); décalage de 90° pour partir du bon endroit sur l'ellipse !
      courbe(t)\y=courbe(t_max)\y-200+200*Sin(#PI*(-angle+90)/180)
      courbe(t)\dx=150*#PI/180*Sin(#PI*(-angle+90)/180)
      courbe(t)\dy=-200*#PI/180*Cos(#PI*(-angle+90)/180)
      longueur_courbe=longueur_courbe+Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\s=longueur_courbe
      courbe(t)\cosinus=courbe(t)\dy / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
    Next angle
    t_max=t

    ; portion horizontale
    While courbe(t)\x<0.75*#largeur_ecran
      t=t+1
      p=p+1
      courbe(t)\x=p
      courbe(t)\y=courbe(t_max)\y
      courbe(t)\dx=1
      courbe(t)\dy=0
      longueur_courbe=longueur_courbe+Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\s=longueur_courbe
      courbe(t)\cosinus=courbe(t)\dy / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
    Wend
    t_max=t

    ;ellipse n°2
    For angle=0 To 360
      t=t+1
      courbe(t)\x=courbe(t_max)\x+100*Cos(#PI*(-angle+90)/180)
      courbe(t)\y=courbe(t_max)\y-50+50*Sin(#PI*(-angle+90)/180)
      courbe(t)\dx=100*#PI/180*Sin(#PI*(-angle+90)/180)
      courbe(t)\dy=-50*#PI/180*Cos(#PI*(-angle+90)/180)
      longueur_courbe=longueur_courbe+Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\s=longueur_courbe
      courbe(t)\cosinus=courbe(t)\dy / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
    Next angle
    t_max=t

    ;deuxième demi-gaussienne
    While courbe(t)\x<#largeur_ecran-1
      t=t+1
      p=p+1
      courbe(t)\x=p
      courbe(t)\y=courbe(t_max)\y-#hauteur_ecran*0.8*Pow(e,-#parametre_gaussienne_2*(p -#largeur_ecran)*(p -#largeur_ecran))
      courbe(t)\dx=1
      courbe(t)\dy=#hauteur_ecran*0.8*#parametre_gaussienne_2*2*(p -#largeur_ecran)*Pow(e,-#parametre_gaussienne_2*(p -#largeur_ecran)*(p -#largeur_ecran))
      longueur_courbe=longueur_courbe+Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\s=longueur_courbe
      courbe(t)\cosinus=courbe(t)\dy / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
    Wend
    t_max=t

    ;-correspondance s<===>(x,y)
    s_max.w=Round(longueur_courbe,#PB_Round_Nearest)
    Dim t_correspondant.l(s_max);tableau qui va permettre de faire le lien entre abscisse curviligne s et coordonnées cartésiennes x,y par le biais du paramètre t
    ; à chaque valeur de s on va faire correspondre une valeur t
    For int_s=1 To s_max
      For i=1 To t_max
        If int_s=Round(courbe(i)\s,#PB_Round_Nearest)
          t_correspondant(int_s)=i
        EndIf
      Next i
    Next int_s

    For int_s=1 To s_max
      If  t_correspondant(int_s)=0
        t_correspondant(int_s)=t_correspondant(int_s-1)
      EndIf
    Next int_s

    ;-PROGRAMME PRINCIPAL
    InitSprite()
    InitSprite3D()
    InitKeyboard()
    OpenWindow(0,0,0,#largeur_ecran,#hauteur_ecran,"Solide_guidé",#PB_Window_ScreenCentered|#PB_Window_SystemMenu  )
    OpenWindowedScreen(WindowID(0),0,0,#largeur_ecran,#hauteur_ecran,0,0,0)

    ;-sprite piste
    CreateSprite(#spr_piste,#largeur_ecran,#hauteur_ecran)
    StartDrawing(SpriteOutput(#spr_piste))
    For t=1 To t_max
      LineXY(x_point_precedent,y_point_precedent,courbe(t)\x,courbe(t)\y,RGB(255,255,255))
      x_point_precedent=courbe(t)\x
      y_point_precedent=courbe(t)\y
    Next t
    FillArea(10,750,RGB(255,255,255),RGB(0,128,0))
    StopDrawing()

     ;-sprites du mobile
    CreateSprite(#spr_carre_droite,32,32,#PB_Sprite_Texture)
    StartDrawing(SpriteOutput(#spr_carre_droite))
    Box(0,0,32,32,RGB(255,255,0))
    Box(16,13,16,6,RGB(255,0,0))
    StopDrawing()
    CreateSprite3D(#spr_carre_droite,#spr_carre_droite)

    CreateSprite(#spr_carre_gauche,32,32,#PB_Sprite_Texture)
    StartDrawing(SpriteOutput(#spr_carre_gauche))
    Box(0,0,32,32,RGB(255,255,255))
    Box(0,13,16,6,RGB(0,0,255))
    StopDrawing()
    CreateSprite3D(#spr_carre_gauche,#spr_carre_gauche)

    t=1
    ;-BOUCLE PRINCIPALE
    Repeat

      Repeat
        Event = WindowEvent()
        If  Event = #PB_Event_CloseWindow
          End
        EndIf
      Until Event = 0

      ;-équations du mouvement
      vs=vs+#g*courbe(t)\cosinus*#dt
      s=s+vs*#dt
      If s<1
        s=1
      EndIf

      ;recherche de la valeur de t
      t=t_correspondant(Int(s))

      ;-affichage des sprites
      DisplaySprite(#spr_piste,0,0)
      Start3D()

      ; calcul de l'angle de rotation du sprite en fonction de l'inclinaison de la courbe
      angle_rotation=180*ATan(courbe(t)\dy/courbe(t)\dx)/#PI
      If courbe(t)\dx<0
        angle_rotation=angle_rotation+180
      EndIf
      ;choix du sprite en fonction du sens de parcours
      If vs >=0
        spr_carre=#spr_carre_droite
      Else
        spr_carre=#spr_carre_gauche
      EndIf
      RotateSprite3D(spr_carre,angle_rotation,0)

      DisplaySprite3D(spr_carre,courbe(t)\x-16,courbe(t)\y-16)
      Stop3D()
      ;-affichage des informations
      StartDrawing(ScreenOutput())
      DrawText(0,700,"distance= "+Str(courbe(t)\s)+ " sur "+Str(longueur_courbe)+" ( "+Str(courbe(t)\s/longueur_courbe*100)+" % )")
      DrawText(0,720,"s="+StrF(s)+" correspond à  t = "+Str(t)+ ">>>> s(t)= "+StrF(courbe(t)\s))
      DrawText(0,740,"vitesse= "+StrF(vs)+" accélération= "+StrF(#g*courbe(t)\cosinus))
      StopDrawing()
      Delay(10)
      FlipBuffers()
    ForEver

Créé le 18 juillet 2008 par Huitbit
Solide glissant sur un rail (avec décollage et chute)

On va s'occuper de la deuxième équation :
m * v²/r = m * g * Sin(a) ? R
Autrement dit :
R = m * g * Sin(a) - m * v² / r
La voiture décolle dès que R = 0 (le sol ne réagit pas car il n'y a plus de contact !)
Ce petit r est TRES IMPORTANT, c'est le rayon de courbure de la trajectoire.
Dans la base de Frenet, la courbe est approximée à chaque instant par un cercle de rayon r.
On a accès à cette valeur de r grâce à la formule ds = dphi_en_radian * r (en fait, c'est la formule "déguisée" de la longueur d'un arc de cercle utilisée depuis l'Antiquité.
exemple : pour un cercle, P = 2*pi*r, pour un demi-cercle, P = pi*r , etc).
ds joue le rôle de la longueur, dphi est un angle de valeur quelconque exprimé EN RADIANS !
Remarque : la base de Frenet change en permanence (activez le commentaire : test du signe du rayon de courbure et vous verrez).
Quoiqu'il en soit, les calculs donnent au final:
décollage si :

Sélectionnez

    Sin(a) < v² / ( r * g )

Après le décollage, il y a la chute libre :
m * |a> = |P>
Rien à signaler !
Puis ... la partie infernale : l'atterrisage !
Les problèmes :

- les points de la courbe ne sont pas tous espacés de la même manière
- le décollage n'est pas assez net
- l'abscisse de l'objet, ne varie pas de la même manière que celle de la courbe
- les obstacles sont différents (creux, bosse, looping)
- les propriétés de l'arctangente avec les angles
- etc

Pour m'en sortir :

- Selon l'obstacle, je décale l'objet pour éviter qu'un atterrisage précoce ait lieu !
- je garde deux valeurs de x pour l'objet et deux valeurs correspondantes de x pour la courbe
- cela me donne deux segments de droite et je vérifie s'ils se croisent
- si le point d'intersection se trouve entre x_ancien et x_nouveau alors il y a contact !

Ca à l'air bête mais avant ça j'ai beaucoup bricolé. Ce qui marchait avec une partie de la courbe, ne marchait pas avec les autres... (activez les StartDrawing() qui traînent et vous verrez !)
Dans les autres messages, je compte m'occuper du rebond (je n'en tiens pas compte ici), et le plus utile, un système de tiles où chaque partie est traîtée à part (bosse, creux, looping,...).
En attendant, pour ceux qui ont le courage de mettre le nez dans le code, un petit complément sur le retour au sol du véhicule :
Pendant le "vol" du véhicule (on dit "la chute libre" si seul le poids intervient dans le mouvement), à chaque boucle du programme, l'abscisse x passe de x_libre_ancien à x_libre. A la verticale de ces coordonnées on trouve un x qui correspond sur la courbe, courbe(t)\x (attention, pour le looping, il y a deux possibiltés !).
Avec les couples (x_ancien, y_ancien)_libre, (x, y)_libre et (x_ancien, y_ancien)_courbe, (x, y)_courbe, j'obtiens deux segments.
Il n' y a plus qu'à tester si les segments se coupent pour savoir s'il y a eu atterissage entre les instants t_ancien et t.
Petits rappels de mathématiques :
Soient deux points A1(x1,y1) et A2(x2,y2)
La droite qui passe par ces points a pour équation : y = a * x + b
Avec a = (y2 - y1) / (x2 - x1) et b = y1 - a * x1 ou b = y2 - a * x2
Soient deux droites d'équations
y = a * x +b
y= c * x + d
(Remarque : Si a = c, ce sont deux droites parallèles => pas d'intersection !)
Pour savoir où elles se coupent , il suffit de résoudre ce système.
On obtient après résolution :
x_intersection = (d - b) / (a - c)
y_intersection = (a *d -b * c) / (a - c)
Dans le programme, je teste si

Sélectionnez

    x_ancien_courbe < x_intersection < x_courbe

L'intérêt de cette méthode, c'est qu'elle ne tient pas compte de l'espacement qu'il peut y avoir entre les points de la courbe (dans la première partie, "la descente", il peut y avoir des écarts de 30 pixels ou plus). Avec les autres méthodes, la voiture passait au travers !
Par contre, je me suis aperçu que lorsque les pentes des droites étaient voisines(décollage, côtés des bosses,...), la détection se faisait mal. Pour corriger ça, je "dope" le décollage du véhicule en rajoutant quelques pixels de plus !
Si quelqu'un a dans ses cartons un test plus efficace, n'hésitez pas !
En fait, je me suis arrêté sur celui-là, car c'est celui qui demandait le moins de bidouilles !
Si vous essayez, n'oubliez pas ce qu'on vous dit là
http://www.myphysicslab.com/RollerFlight.html
Limitations of this Simulation
Unlike the other roller coaster simulations, this one does not have the option to use various tracks. The reason is that having a track that doesn't loop simplified the code considerably. For example, to determine whether there is a collision, we only test whether the ball is below the track. With a looped track there would be more complicated criteria for deciding if the ball has collided with the track, such as checking if it is inside or outside the track. So if you are looking for a programming project, grab the source code and go to work!

Sélectionnez

    ;solide guidé motorisé
    ;auteur Huitbit
    ;pb v4.20
    ;-déclarations*********************************
    #largeur_ecran=1024
    #hauteur_ecran=768
    #dim_sprite=32 ;sprite carré de 32*32
    Enumeration
      #spr_decor
      #spr_car_droite
      #spr_car_gauche
      #chute_libre
      #solide_guide
    EndEnumeration
    Structure donnees
      x.f
      y.f
      dx.f
      dy.f
      s.f ; abscisse curviligne s(t)
      cosinus.f ; cosinus de l'angle vecteur poids |P> et le vecteur tangent à la courbe
      sinus.f ; sinus de l'angle vecteur poids |P> et le vecteur tangent à la courbe
      phi_radian.f ;angle correspondant à la pente locale de la courbe, en radians
    EndStructure
    x_libre_ancien.f
    y_libre_ancien.f
    x_libre.f
    y_libre.f
    x_decalage.f
    y_decalage.f
    angle0_libre.f
    t0_libre.w
    tx_libre.w
    tx_libre_ancien.w
    v0s.f
    v0x_libre.f
    vx_libre.f
    vy_libre.f
    angle_rotation_libre.w
    a_libre.f
    b_libre.f
    a_courbe.f
    b_courbe.f
    x_contact.f
    y_contact.f
    retard_detection.b
    acceleration_moteur.f
    #acceleration_moteur_max=8
    #dt=0.2
    #coeff_frot=0.1
    spr_car.b
    #g=9.8
    x_car.f
    y_car.f

    Macro collision
    a_libre= (y_libre- y_libre_ancien)/(x_libre-x_libre_ancien)
    b_libre=y_libre-a_libre*x_libre
    If tx_libre<>tx_libre_ancien
      a_courbe=(courbe(tx_libre)\y-courbe(tx_libre_ancien)\y)/(courbe(tx_libre)\x-courbe(tx_libre_ancien)\x)
      b_courbe=courbe(tx_libre)\y-a_courbe*courbe(tx_libre)\x
    EndIf
    ;-zone de la courbe survolée
    ; StartDrawing(SpriteOutput(#spr_decor))
    ; LineXY(courbe(tx_libre)\x,courbe(tx_libre)\y,courbe(tx_libre_ancien)\x,courbe(tx_libre_ancien)\y,RGB(255,0,0))
    ; StopDrawing()

    x_contact=(b_courbe-b_libre)/(a_libre-a_courbe)
    ;y_contact=a_courbe*x_contact+b_courbe

    If courbe(tx_libre)\x>courbe(tx_libre_ancien)\x
      If x_contact< courbe(tx_libre)\x And x_contact>courbe(tx_libre_ancien)\x
        t=tx_libre
        s=courbe(tx_libre)\s
        vs=Sqr(vx_libre*vx_libre+vy_libre*vy_libre)*Abs(Cos(angle_rotation_libre*#PI/180))
        retard_detection=0
        modele=#solide_guide
        ;-tracé du point d'impact
        ;     StartDrawing(SpriteOutput(#spr_decor))
        ;     DrawingMode(#PB_2DDrawing_Outlined   )
        ;     Circle(courbe(tx_libre)\x,courbe(tx_libre)\y,8,RGB(0,255,255))
        ;     StopDrawing()
      EndIf
    EndIf

    If courbe(tx_libre)\x<courbe(tx_libre_ancien)\x
      If x_contact> courbe(tx_libre)\x And x_contact<courbe(tx_libre_ancien)\x
        t=tx_libre
        s=courbe(tx_libre)\s
        vs=-Sqr(vx_libre*vx_libre+vy_libre*vy_libre)*Abs(Cos(angle_rotation_libre*#PI/180))
        retard_detection=0
        modele=#solide_guide
        ;tracé du point d'impact
        ;     StartDrawing(SpriteOutput(#spr_decor))
        ;     DrawingMode(#PB_2DDrawing_Outlined   )
        ;     Circle(courbe(tx_libre)\x,courbe(tx_libre)\y,8,RGB(0,255,0))
        ;     StopDrawing()
      EndIf
    EndIf

    EndMacro

    ;-création de la piste
    Dim courbe.donnees(5000)
    #y_depart=64
    e.f=2.718281828 ; valeur de exp(1)
    #parametre_gaussienne=0.001
    #parametre_bosse=0.0004
    #parametre_creux=0.0004
    #hauteur_bosse=64
    #profondeur_creux=48
    t.w = 0 ;paramètre pour les fonctions x(t), y(t) et s(t) sur tout le parcours
    t_max.w ; dernière valeur de t
    p.w = 0 ; paramètre provisoire pour chaque portion de courbes
    x_point_precedent.f=0
    y_point_precedent.f=#y_depart
    angle.w
    #rayon=100
    longueur_courbe.f = 0

    s.f ; abscisse curviligne s(t)
    s_max.w ; abscisse curviligne s(t) maximale
    int_s.w; valeur entière de s(t)
    vs.f ; vitesse curviligne
    angle_rotation.w
    rayon.f;  rayon de courbure de la trajectoire r=ds/dphi
    modele.b=#solide_guide

    ;-première demi-gaussienne
    While courbe(t)\x<#largeur_ecran/8
      t=t+1
      p=p+1
      courbe(t)\x=p
      courbe(t)\y=#y_depart+(#hauteur_ecran*2/3-#y_depart)*(1-Pow(e,-#parametre_gaussienne*p*p))
      courbe(t)\dx=1
      courbe(t)\dy=(#hauteur_ecran*2/3-#y_depart)*#parametre_gaussienne*2*p*Pow(e,-#parametre_gaussienne*p*p)
      longueur_courbe=longueur_courbe+Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\s=longueur_courbe
      courbe(t)\cosinus=courbe(t)\dy / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\sinus=courbe(t)\dx / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\phi_radian =ATan(courbe(t)\dy/courbe(t)\dx)
    Wend
    t_max=t

    ;- creux
    While courbe(t)\x<3/8*#largeur_ecran
      t=t+1
      p=p+1
      courbe(t)\x=p
      courbe(t)\y=courbe(t_max)\y+#profondeur_creux*Pow(e,-#parametre_creux*(p-#largeur_ecran/4)*(p-#largeur_ecran/4))
      courbe(t)\dx=1
      courbe(t)\dy=-#profondeur_creux*2*#parametre_creux*(p-#largeur_ecran/4)*Pow(e,-#parametre_creux*(p-#largeur_ecran/4)*(p-#largeur_ecran/4))
      longueur_courbe=longueur_courbe+Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\s=longueur_courbe
      courbe(t)\cosinus=courbe(t)\dy / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\sinus=courbe(t)\dx / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\phi_radian =ATan(courbe(t)\dy/courbe(t)\dx)

    Wend
    t_max=t

    ;-bosse
    While courbe(t)\x<5*#largeur_ecran/8
      t=t+1
      p=p+1
      courbe(t)\x=p
      courbe(t)\y=courbe(t_max)\y-#hauteur_bosse*Pow(e,-#parametre_bosse*(p-#largeur_ecran/2)*(p-#largeur_ecran/2))
      courbe(t)\dx=1
      courbe(t)\dy=#hauteur_bosse*2*#parametre_bosse*(p-#largeur_ecran/2)*Pow(e,-#parametre_bosse*(p-#largeur_ecran/2)*(p-#largeur_ecran/2))
      longueur_courbe=longueur_courbe+Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\s=longueur_courbe
      courbe(t)\cosinus=courbe(t)\dy / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\sinus=courbe(t)\dx / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\phi_radian =ATan(courbe(t)\dy/courbe(t)\dx)

    Wend
    t_max=t

    ;- portion horizontale
    While courbe(t)\x<0.75*#largeur_ecran
      t=t+1
      p=p+1
      courbe(t)\x=p
      courbe(t)\y=courbe(t_max)\y
      courbe(t)\dx=1
      courbe(t)\dy=0
      longueur_courbe=longueur_courbe+Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\s=longueur_courbe
      courbe(t)\cosinus=courbe(t)\dy / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\sinus=courbe(t)\dx / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\phi_radian =ATan(courbe(t)\dy/courbe(t)\dx)

    Wend
    t_max=t

    ;-cercle
    For angle=0 To 360
      t=t+1
      courbe(t)\x=courbe(t_max)\x+#rayon*Cos(#PI*(-angle+90)/180); décalage de 90° pour partir du bon endroit sur l'ellipse !
      courbe(t)\y=courbe(t_max)\y-#rayon+#rayon*Sin(#PI*(-angle+90)/180)
      courbe(t)\dx=#rayon*#PI/180*Sin(#PI*(-angle+90)/180)
      courbe(t)\dy=-#rayon*#PI/180*Cos(#PI*(-angle+90)/180)
      longueur_courbe=longueur_courbe+Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\s=longueur_courbe
      courbe(t)\cosinus=courbe(t)\dy / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\sinus=courbe(t)\dx / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      ; prise en compte des valeurs +INF et -INF dans le calcul de arctangente(phi)
      If courbe(t)\dx<>0
        courbe(t)\phi_radian =ATan(courbe(t)\dy/courbe(t)\dx)
      Else
        If  courbe(t)\dy>0
          courbe(t)\phi_radian=#PI/2
        Else
          courbe(t)\phi_radian=-#PI/2
        EndIf
      EndIf
    Next angle
    t_max=t

    ;-deuxième demi-gaussienne
    While courbe(t)\x<#largeur_ecran-1
      t=t+1
      p=p+1
      courbe(t)\x=p
      courbe(t)\y=courbe(t_max)\y-(#hauteur_ecran*2/3-#y_depart)*Pow(e,-#parametre_gaussienne*(p -#largeur_ecran)*(p -#largeur_ecran))
      courbe(t)\dx=1
      courbe(t)\dy=(#hauteur_ecran*2/3-#y_depart)*2*#parametre_gaussienne*(p -#largeur_ecran)*Pow(e,-#parametre_gaussienne*(p -#largeur_ecran)*(p -#largeur_ecran))
      longueur_courbe=longueur_courbe+Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\s=longueur_courbe
      courbe(t)\cosinus=courbe(t)\dy / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\sinus=courbe(t)\dx / Sqr(courbe(t)\dx*courbe(t)\dx+courbe(t)\dy*courbe(t)\dy)
      courbe(t)\phi_radian =ATan(courbe(t)\dy/courbe(t)\dx)

    Wend
    t_max=t

    ;-correspondance s <===> t
    s_max=Round(longueur_courbe,#PB_Round_Nearest)
    Dim t_correspondant_a_s.l(s_max);tableau qui va permettre de faire le lien entre abscisse curviligne s et coordonnées cartésiennes x,y par le biais du paramètre t
    ; à chaque valeur de s on va faire correspondre une valeur t
    For int_s=1 To s_max
      For i=1 To t_max
        If int_s=Round(courbe(i)\s,#PB_Round_Nearest)
          t_correspondant_a_s(int_s)=i
        EndIf
      Next i
    Next int_s

    For int_s=1 To s_max
      If  t_correspondant_a_s(int_s)=0
        t_correspondant_a_s(int_s)=t_correspondant_a_s(int_s-1)
      EndIf

    Next int_s

    ;-PROGRAMME PRINCIPAL
    InitSprite()
    InitSprite3D()
    InitKeyboard()
    OpenWindow(0,0,0,#largeur_ecran,#hauteur_ecran,"solide guidé motorisé | <= et => pour se déplacer !",#PB_Window_ScreenCentered|#PB_Window_SystemMenu  )
    OpenWindowedScreen(WindowID(0),0,0,#largeur_ecran,#hauteur_ecran,0,0,0)

    ;-sprite décor
    CreateSprite(#spr_decor,#largeur_ecran,#hauteur_ecran)
    StartDrawing(SpriteOutput(#spr_decor))
    For etoile=1 To 500
    Plot(5+Random(#largeur_ecran-10),5+Random(#hauteur_ecran-10),RGB(25,255,255))
    Next etoile
    For t=1 To t_max
      LineXY(x_point_precedent, y_point_precedent, courbe(t)\x, courbe(t)\y,RGB(0,255,255))
      x_point_precedent.f=courbe(t)\x
      y_point_precedent.f=courbe(t)\y
    Next t
    FillArea(10,600,RGB(0,255,255),RGB(0,55,55))
    StopDrawing()

    ;-sprite voiture
    CreateSprite(#spr_car_droite,32,32,#PB_Sprite_Texture)
    StartDrawing(SpriteOutput(#spr_car_droite))
    Box(0,4,16,12,RGB(75, 241, 75))
    Ellipse(16,16,16,12,RGB(248, 241, 7))
    Circle(8,24,8,RGB(15, 109, 240))
    Circle(24,26,6,RGB(15, 109, 240))
    Box(20,11,6,5,RGB(174, 192, 248))
    StopDrawing()
    CreateSprite3D(#spr_car_droite, #spr_car_droite)

    CreateSprite(#spr_car_gauche,32,32,#PB_Sprite_Texture)
    StartDrawing(SpriteOutput(#spr_car_gauche))
    Box(16,4,16,12,RGB(75, 241, 75))
    Ellipse(16,16,16,12,RGB(248, 241, 7))
    Circle(24,24,8,RGB(15, 109, 240))
    Circle(8,26,6,RGB(15, 109, 240))
    Box(6,11,6,5,RGB(174, 192, 248))
    StopDrawing()
    CreateSprite3D(#spr_car_gauche, #spr_car_gauche)

    ;-abscisse curviligne initiale
    s=1129
    t=t_correspondant_a_s(Int(s))

    ;-BOUCLE PRINCIPALE

    ;gestion des évènements de la fenêtre
    Repeat
      Repeat
        Event = WindowEvent()
        If  Event = #PB_Event_CloseWindow
          End
        EndIf
      Until Event = 0

      ;-gestion du clavier
      ExamineKeyboard()
      If KeyboardPushed(#PB_Key_Left)
        acceleration_moteur=acceleration_moteur-2
        If acceleration_moteur<-#acceleration_moteur_max
          acceleration_moteur=-#acceleration_moteur_max
        EndIf
      ElseIf  KeyboardPushed(#PB_Key_Right)
        acceleration_moteur=acceleration_moteur+2
        If acceleration_moteur>#acceleration_moteur_max
          acceleration_moteur=#acceleration_moteur_max
        EndIf
      Else
        acceleration_moteur=0
      EndIf

      ;-équations du mouvement

      If modele=#solide_guide
        vs=vs+(#g*courbe(t)\cosinus-#coeff_frot*vs+acceleration_moteur)*#dt
        s=s+vs*#dt

        If s<1
          s=1
        EndIf
        If s>s_max
          s=s_max
        EndIf
        ;recherche de la valeur de t
        t=t_correspondant_a_s(Int(s))

        angle_rotation=180*courbe(t)\phi_radian /#PI
        If courbe(t)\dx<0
          angle_rotation=angle_rotation+180
        EndIf
        ;choix du sprite en fonction du sens de parcours
        If vs >=0
          spr_car=#spr_car_droite
        Else
          spr_car=#spr_car_gauche
        EndIf

      EndIf

      If modele=#chute_libre
        retard_detection=retard_detection+1
        x_libre_ancien=x_libre
        y_libre_ancien=y_libre
        tx_libre_ancien=tx_libre
        vy_libre=vy_libre+#g*#dt
        x_libre=x_libre+vx_libre*#dt
        y_libre=y_libre+vy_libre*#dt
        angle_rotation_libre=ATan(vy_libre/vx_libre)*180/#PI
        If courbe(t0_libre)\dx<0
          angle_rotation_libre=angle_rotation_libre+180
        EndIf

        ;-reprise de contact avec le sol
        ;- bosse sens retour
        If  v0s<0 And v0x_libre<0
          For t_test=  tx_libre_ancien To 0 Step -1
            If courbe(t_test)\x< x_libre
              tx_libre=t_test
              Break
            EndIf
          Next t_test
          collision
        EndIf

        ;- bosse  sens aller
        If v0s>0 And v0x_libre>0
          For t_test=tx_libre_ancien To t_max
            If  courbe(t_test)\x>x_libre
              tx_libre=t_test
              Break
            EndIf
          Next t_test
          collision
        EndIf

        ;-looping sens aller
        If  v0s>=0 And v0x_libre=<0  And retard_detection>1
          For t_test=  tx_libre_ancien To 0 Step -1
            If courbe(t_test)\x<= x_libre
              tx_libre=t_test
              Break
            EndIf
          Next t_test
          collision
        EndIf

        ;-looping sens retour
        If  v0s=<0 And v0x_libre>=0  And retard_detection>1
          For t_test=tx_libre_ancien To t_max
            If  courbe(t_test)\x>=x_libre
              tx_libre=t_test
              Break
            EndIf
          Next t_test
          collision
        EndIf

        ;réinitialisation en cas de non détection
        If y_libre>750
          modele=#solide_guide
          s=1129
          t=t_correspondant_a_s(Int(s))
          vs=0
          v0s=0
          v0x_libre=0
          retard_detection=0
        EndIf
      EndIf

      ;-gestion de la perte de contact avec le sol
      ; condition sur la variation d'angle pour empêcher le passage de -90° à +90°
      If (courbe(t+1)\phi_radian-courbe(t-1)\phi_radian)<1  And modele=#solide_guide
        ;calcul du rayon de courbure
        rayon=(courbe(t+1)\s-courbe(t-1)\s)/(courbe(t+1)\phi_radian-courbe(t-1)\phi_radian)

        ;-test du signe du rayon de courbure (nous renseigne sur le sens du vecteur |en>)
        ;             StartDrawing(SpriteOutput(#spr_decor))
        ;             If rayon>0
        ;               Box(courbe(t)\x,courbe(t)\y-20,2,4,RGB(255,0,0))
        ;             Else
        ;               Box(courbe(t)\x,courbe(t)\y-20,2,4,RGB(0,255,0))
        ;             EndIf
        ;             StopDrawing()

        ;-condition de la perte de contact
        If  courbe(t)\sinus<vs*vs/(rayon*#g)
          ;conditions initiales de la chute libre
          angle0_libre=courbe(t)\phi_radian
          If courbe(t)\dx<0
            angle0_libre=angle0_libre+#PI
          EndIf
          t0_libre=t
          tx_libre=t
          v0s=vs
          v0x_libre=vs*Cos(angle0_libre)
          vx_libre=v0x_libre
          vy_libre=vs*Sin(angle0_libre)

          ;léger décalage pour améliorer la détection
          If  v0s* v0x_libre>0  ;bosse et creux
            x_decalage=0
            y_decalage=-#dim_sprite*0.2
          Else ;looping
            x_decalage=0
            y_decalage=0
          EndIf

          x_libre=courbe(t)\x+x_decalage
          y_libre=courbe(t)\y+y_decalage

          x_libre_ancien=x_libre
          y_libre_ancien=y_libre
          angle_rotation_libre=angle0_libre*180/#PI
          modele=#chute_libre
          ;-visualisation du point de décollage
          ;       StartDrawing(SpriteOutput(#spr_decor))
          ;       DrawingMode(#PB_2DDrawing_Outlined   )
          ;       Circle(courbe(tx_libre)\x,courbe(tx_libre)\y,4,RGB(255,0,0))
          ;       StopDrawing()

        EndIf
      EndIf

      DisplaySprite(#spr_decor,0,0)
      If modele=#solide_guide
        x_car=courbe(t)\x-16
        y_car=courbe(t)\y-16
        angle_rotation_car=angle_rotation
      ElseIf modele=#chute_libre
        x_car=x_libre-16
        y_car=y_libre-16
        angle_rotation_car=angle_rotation_libre
      EndIf
      Start3D()
      RotateSprite3D(spr_car,angle_rotation_car,0)
      DisplaySprite3D(spr_car,x_car,y_car)
      Stop3D()

      Delay(10)
      FlipBuffers()
    ForEver

    End

Créé le 9 août 2008 par Huitbit
Version hors-ligne

Les sources présentés sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre cette page de présentation de ces sources constitue une œuvre intellectuelle protégée par les droits d'auteurs. Copyright ©2008 Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.