Sources PureBasic
Sources PureBasicConsultez toutes les sources
Nombre d'auteurs : 41, nombre de sources : 88, dernière mise à jour : 13 août 2011
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 !)
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 !
;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
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 :
;-équations du mouvement
vs=
vs+
#g
*
courbe(t)\cosinus*
#dt
par :
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 !
;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
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 :
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
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!
;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