IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Sources PureBasic

Sources PureBasicConsultez toutes les sources

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

 
OuvrirSommairePhysique

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

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

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

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2008 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site ni 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.