
L'objectif : Pouvoir indiquer à l'aide d'une souris la destination que doit atteindre un avion.
Contrainte : L'avion doit se déplacer selon un rayon de courbure constant pour prendre un virage.
L'avion se déplace à vitesse constante , aussi bien en ligne droite que dans un virage.
La touche [F1] permet de visualiser le cercle autour duquel l'avion doit tourner.
Pour le fun j'ai aussi ajouté la modification de la taille de l'avion par les flèches haut et bas.
Code : Tout sélectionner
;Comtois et Lutin 12 mai 2007
;PB 4.02
EnableExplicit
;{ Fichier Include à créer éventuellement ici
Enumeration
#Souris
#Destination
EndEnumeration
Structure s_Vecteur
x.f
y.f
EndStructure
Structure s_Avion
Pos.s_Vecteur
Vitesse.f
Omega.f
Rayon.f
Direction.s_Vecteur
NbSommet.l
Scale.l
Angle.f
Cherche.l
Sommet.s_Vecteur[12]
EndStructure
Macro COPIE_VECTEUR(V, V1)
V\x = V1\x
V\y = V1\y
EndMacro
Macro ADDITION_VECTEUR(V, V1, V2)
V\x = V1\x + V2\x
V\y = V1\y + V2\y
EndMacro
Macro SOUSTRACTION_VECTEUR(V, V1, V2)
V\x = V1\x - V2\x
V\y = V1\y - V2\y
EndMacro
Macro PRODUIT_SCALAIRE(V1, V2)
(V1\x * V2\x + V1\y * V2\y)
EndMacro
Define.s_Vecteur Destination, AvionDestination, CercleDestination, Cercle, Normale, T1, Temp
Define.s_Vecteur MemoireDirectionTangente
Define.f DistanceCercleDestination, DistanceAvionDestination, Angle1, Angle2
Define.f DistancePointDestination, ProduitScalaire, AngleAvion, AngleTangente, CosA, SinA
Define.l i, CalculNormale, Affiche
Define.s_Avion Avion
Define.l ScreenX, ScreenY
Declare.f atan2f(y.f, x.f)
Declare InitAvion(*Avion.s_Avion)
;}
;{ Init et ouverture écran
If ExamineDesktops()
ScreenX = DesktopWidth(0)
ScreenY = DesktopHeight(0)
Else
ScreenX = 1024
ScreenY = 728
EndIf
If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0
MessageRequester( "Erreur" , "Impossible d'initialiser DirectX 7 Ou plus" , 0 )
End
ElseIf OpenScreen( ScreenX,ScreenY, 32, "Math" ) = 0
MessageRequester( "Erreur" , "Impossible d'ouvrir l'écran " , 0 )
End
EndIf
;}
;{ Les spritess
CreateSprite(#SOuris,16,16)
StartDrawing(SpriteOutput(#SOuris))
Line(0,0,15,0,#White)
Line(0,0,0,15,#White)
LineXY(0,15,15,0,#White)
FillArea(7,7,#White,#Blue)
StopDrawing()
;Sprite Destination
CreateSprite(#Destination,16,16)
StartDrawing(SpriteOutput(#Destination))
LineXY(0,0,15,15,#Yellow)
LineXY(0,15,15,0,#Yellow)
StopDrawing()
;}
;{ Les procédures
Procedure InitAvion(*Avion.s_Avion)
Define i
Define.f x, y
*Avion\NbSommet = 12
*Avion\Scale = 40
Restore sommets
For i = 0 To 11
Read *Avion\sommet[i]\x
Read *Avion\sommet[i]\y
Next i
;Position de l'avion
*Avion\Pos\x = 220
*Avion\Pos\y = 210
;Rayon du cercle
*Avion\Rayon = 5 * *Avion\Scale
;Vitesse
*Avion\Vitesse = 3.5
*Avion\Omega = *Avion\Vitesse / *Avion\Rayon
;Direction
*Avion\Direction\x = 1
*Avion\Direction\y = 0
;Angle
*Avion\Angle = 0
EndProcedure
Procedure.f atan2f(y.f, x.f)
!fld dword[p.v_y]
!fld dword[p.v_x]
!fpatan
ProcedureReturn
EndProcedure
Procedure.f Distance(*A.s_Vecteur, *B.s_Vecteur)
Define.f Dist
Dist = Sqr((*A\x-*B\x)*(*A\x-*B\x)+(*A\y-*B\y)*(*A\y-*B\y))
ProcedureReturn Dist
EndProcedure
Procedure.f Norme(*V.s_Vecteur)
ProcedureReturn Sqr(*V\x * *V\x + *V\y * *V\y)
EndProcedure
Procedure Normalise(*V.s_Vecteur)
Define.f Longueur
Longueur = Sqr(*V\x * *V\x + *V\y * *V\y)
;Normalise
If Longueur
*V\x / Longueur
*V\y / Longueur
EndIf
EndProcedure
Procedure RotationAutourOrigine(*Point.s_Vecteur, Angle.f)
;Je pourrais utiliser la procédure RotationAutourPoint en utilisant un vecteur nul
Define.f CosA, SinA
Define.s_Vecteur Temporaire
CosA = Cos(Angle)
SinA = Sin(Angle)
Temporaire\x = *Point\x * CosA - *Point\y * SinA
Temporaire\y = *Point\x * SinA + *Point\y * CosA
COPIE_VECTEUR(*Point, Temporaire)
EndProcedure
Procedure RotationAutourPoint(*Origine.s_Vecteur, *Point.s_Vecteur, Angle.f)
Define.f CosA, SinA
Define.s_Vecteur Temporaire
CosA = Cos(Angle)
SinA = Sin(Angle)
Temporaire\x = *Origine\x + (*Point\x - *Origine\x) * CosA - (*Point\y - *Origine\y) * SinA
Temporaire\y = *Origine\y + (*Point\x - *Origine\x) * SinA + (*Point\y - *Origine\y) * CosA
COPIE_VECTEUR(*Point, Temporaire)
EndProcedure
Procedure Translation(*Point.s_Vecteur, *Direction.s_Vecteur, Distance.f)
*Point\x + *Direction\x * Distance
*Point\y + *Direction\y * Distance
EndProcedure
Procedure DrawAvion(*A.s_Avion)
Define.l i, x, y, x1, y1
Define.f CosA, SinA
CosA = Cos(*A\Angle)
SinA = Sin(*A\Angle)
For i = 0 To *A\NbSommet-2
x = *A\Pos\x + *A\Sommet[i]\x * *A\Scale * CosA - *A\Sommet[i]\y * *A\Scale * SinA
y = *A\Pos\y + *A\Sommet[i]\x * *A\Scale * SinA + *A\Sommet[i]\y * *A\Scale * CosA
x1 = *A\Pos\x + *A\Sommet[i+1]\x * *A\Scale * CosA - *A\Sommet[i+1]\y * *A\Scale * SinA
y1 = *A\Pos\y + *A\Sommet[i+1]\x * *A\Scale * SinA + *A\Sommet[i+1]\y * *A\Scale * CosA
LineXY(x, y, x1, y1, #White)
Next i
x = *A\Pos\x + *A\Sommet[*A\NbSommet-1]\x * *A\Scale * CosA - *A\Sommet[*A\NbSommet-1]\y * *A\Scale * SinA
y = *A\Pos\y + *A\Sommet[*A\NbSommet-1]\x * *A\Scale * SinA + *A\Sommet[*A\NbSommet-1]\y * *A\Scale * CosA
x1 = *A\Pos\x + *A\Sommet[0]\x * *A\Scale * CosA - *A\Sommet[0]\y * *A\Scale * SinA
y1 = *A\Pos\y + *A\Sommet[0]\x * *A\Scale * SinA + *A\Sommet[0]\y * *A\Scale * CosA
LineXY(x, y, x1, y1, #White)
Line(*A\Pos\x,*A\Pos\y,*A\Direction\x* *A\Scale * 3, *A\Direction\y* *A\Scale * 3, #White)
EndProcedure
;}
InitAvion(@Avion)
Repeat
ClearScreen(0)
If ExamineKeyboard()
If KeyboardReleased(#PB_Key_F1)
Affiche = 1 - Affiche
EndIf
If KeyboardPushed(#PB_Key_Up) And Avion\Scale < 100
Avion\Scale + 1
ElseIf KeyboardPushed(#PB_Key_Down) And Avion\Scale > 1
Avion\Scale - 1
EndIf
EndIf
If ExamineMouse()
If MouseButton(#PB_MouseButton_Left)
Avion\Cherche = #True
CalculNormale = #False
Destination\x = MouseX()
Destination\y = MouseY()
EndIf
EndIf
;La cible est atteinte ?
If Distance(@Avion\Pos, @Destination) <= Avion\Vitesse + 0.1
COPIE_VECTEUR(Destination, Avion\Pos)
EndIf
If Avion\Cherche
;On calcule la position du cercle et la tangente à chaque changement de destination
If CalculNormale = #False
;-Calcule la normale
Normale\x = -Avion\Direction\y
Normale\y = Avion\Direction\x
Normalise(@Normale)
;-Calcul la position du cercle en fonction de la destination
SOUSTRACTION_VECTEUR(AvionDestination, Destination, Avion\Pos)
ProduitScalaire = PRODUIT_SCALAIRE(AvionDestination, Normale)
DistanceAvionDestination = Norme(AvionDestination)
ProduitScalaire / Abs(ProduitScalaire) ; Vaut 1 ou -1 selon le côté où se trouve la destination
If ProduitScalaire <> 0
Cercle\x = Avion\Pos\x + Normale\x * ProduitScalaire * Avion\Rayon
Cercle\y = Avion\Pos\y + Normale\y * ProduitScalaire * Avion\Rayon
;-Calcul la tangente
SOUSTRACTION_VECTEUR(CercleDestination, Destination, Cercle)
DistanceCercleDestination = Norme(CercleDestination)
Angle1 = ASin(Avion\Rayon / DistanceCercleDestination)
DistancePointDestination = Cos(Angle1) * DistanceCercleDestination
Angle2 = #PI - atan2f(-CercleDestination\y, CercleDestination\x)
;Coordonnées du point tangent
T1\x = Destination\x + Cos(Angle2 + Angle1 * ProduitScalaire) * DistancePointDestination
T1\y = Destination\y + Sin(Angle2 + Angle1 * ProduitScalaire) * DistancePointDestination
;Avant je ne le mettais pas et ça fonctionnait quand même, mais j'avais un doute pour certains cas !
SOUSTRACTION_VECTEUR(MemoireDirectionTangente, Destination, T1)
Normalise(MemoireDirectionTangente)
CalculNormale = #True
EndIf
EndIf
;Il faut avancer pour se dégager si la destination se trouve dans le cercle
If Distance(@Destination , @Cercle) < Avion\Rayon Or ProduitScalaire = 0
CalculNormale = #False ; Pour autoriser le calcul de la nouvelle position du cercle
;Déplacement de l'avion en ligne droite
Translation(@Avion\Pos, @Avion\Direction, Avion\Vitesse)
Else
;Tourne sur le cercle jusqu'à trouver la tangente en direction de la destination
;Mise à jour de la direction
RotationAutourOrigine(@Avion\Direction, Avion\Omega*ProduitScalaire)
;Mise à jour de l'angle
Avion\Angle = atan2f(Avion\Direction\y, Avion\Direction\x)
;Repositionne l'avion autour du cercle
RotationAutourPoint(@Cercle, @Avion\Pos, Avion\Omega*ProduitScalaire)
;LE point tangent est atteint
;If Distance(@Avion\Pos, @T1) <= Avion\Vitesse/2
AngleAvion = atan2f(Cercle\y-Avion\Pos\y, Cercle\x-Avion\Pos\x)
AngleTangente = atan2f(Cercle\y-T1\y, Cercle\x-T1\x)
If AngleAvion=AngleTangente Or (AngleAvion > AngleTangente - Avion\Omega/2 And AngleAvion < AngleTangente + Avion\Omega/2)
CalculNormale = #False
Avion\Cherche = #False
COPIE_VECTEUR(Avion\Pos, T1)
;SOUSTRACTION_VECTEUR(Avion\Direction, Destination, T1)
;Normalise(@Avion\Direction)
COPIE_VECTEUR(Avion\Direction, MemoireDirectionTangente);Remplace les 2 lignes commentées au dessus
;Mise à jour de l'angle
Avion\Angle = atan2f(Avion\Direction\y, Avion\Direction\x)
EndIf
EndIf
Else
;Déplacement de l'avion en ligne droite
Translation(@Avion\Pos, @Avion\Direction, Avion\Vitesse)
EndIf
StartDrawing(ScreenOutput())
DrawingMode(#PB_2DDrawing_Outlined)
BackColor(0)
If Affiche
;Cercle retenu
Circle(Cercle\x,Cercle\y, Avion\Rayon, #Yellow)
;Tangente
LineXY(Destination\x, Destination\y, T1\x, T1\y, #Green)
EndIf
DrawAvion(@Avion)
StopDrawing()
DisplayTransparentSprite(#Destination, Destination\x-8, Destination\y-8)
DisplayTransparentSprite(#SOuris,MouseX(), MouseY())
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
;Définition des sommets de l'avion
DataSection
sommets:
Data.f -3, 0.5
Data.f 0, 0.5
Data.f 0, 2.5
Data.f 1, 2.5
Data.f 2, 0.5
Data.f 3, 0.5
Data.f 3, -0.5
Data.f 2, -0.5
Data.f 1, -2.5
Data.f 0, -2.5
Data.f 0, -0.5
Data.f -3, -0.5
EndDataSection