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)
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

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 !

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 !
Remarque : j'ai découvert que la fonction exponentielle (très utilisée en maths et en physique) n'existait pas dans PB


Code : Tout sélectionner
;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
PS : avec la partie II (gestion du contact solide-courbe), vous pourrez faire plein de Sonic
