[Résolu] if..else..endif et trigonométrie code de Cpl.Bator

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Geo Trouvpatou
Messages : 471
Inscription : dim. 23/déc./2007 18:10

[Résolu] if..else..endif et trigonométrie code de Cpl.Bator

Message par Geo Trouvpatou »

Salut.

Avant toute chose voici le code.
Pour voir l'algo entier non-modifié, voir l'adresse dans le code.
Si vous récupérez le code là-bas, il faudra remplacer les 2 back-slashs par un seul :

Code : Tout sélectionner

; Algo tiré d'un code de Cpl.Bator : http://www.game-corp.net/topic-744-purebasic-poursuite-d-039-un-point-par-un-autre.html

EnableExplicit
Enumeration
      #Voiture
      #Voiture3D_IA
EndEnumeration

#SW = 640
#SH = 480
UsePNGImageDecoder()

InitSprite() : InitKeyboard() : InitMouse()
If InitSprite3D() = 0
      MessageRequester("Erreur", "La librairie Sprite3D n'a pas pu être initialisée", 0)
      End
EndIf
;OpenWindow(0, 0, 0, 640, 480, "Un écran dans une fenêtre...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
;OpenWindowedScreen(WindowID(0), 0, 0, #SW, #SH, 0, 0, 0)

OpenScreen(#SW, #SH, 32, "")

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
      Structure point
            x.f
            y.f
      EndStructure
CompilerEndIf


;-Structures
; Structure VECTOR2
;       x.f
;       y.f
; EndStructure

Structure ENTITY
      ;Position.VECTOR2
      x.f
      y.f
      Angle.f
EndStructure


;-Declarations des fonctions
Declare.f curveangle(newangle.f,oldangle.f,increments.f)
Declare.f ReturnDegAngle(x1.f,y1.f,x2.f,y2.f)
Declare track_SmoothPoint(*A.ENTITY,*B.ENTITY, turnspeed.f=1.0)

#turnspeed = 4.0

; ************************************************************************************
; Arrow (En réalité la voiture).
; Ses coordonnées pour la position de départ
Global Arrow.ENTITY
Arrow\x = 100
Arrow\y = 250
Arrow\Angle = 0

; Tableau pour stocker les différents checkpoint à atteindre
Global Dim Target.ENTITY(5)
;Target(1)\x = MouseX()
;Target(1)\y = MouseY()
Target(1)\x = 500
Target(1)\y = 50

Target(2)\x = 550
Target(2)\y = 200

Target(3)\x = 300
Target(3)\y = 250

Target(4)\x = 300 
Target(4)\y = 50

Target(5)\x = 10
Target(5)\y = 10

Global checkpoint = 1
Global Quit

;LoadSprite(#Voiture, "voitureFin.png", #PB_Sprite_Texture)

; Super voiture de sport rouge dont on ne citera pas la marque.
CreateSprite(#Voiture, 16, 16, #PB_Sprite_Texture)
StartDrawing(SpriteOutput(#Voiture))
Box(3, 0, 16, 10, RGB(255, 0, 0))
StopDrawing()

; Création du Sprite 3d
CreateSprite3D(#Voiture3D_IA, #Voiture)

; Ci-dessous si on utilise le programme dans le mode fenêtré.
;ReleaseMouse(1)

Repeat
      ClearScreen(0)
      ExamineKeyboard()
      ExamineMouse()
      
      
      StartDrawing(ScreenOutput())
      
      
      ; Le 1er checkpoint à atteindre
      If checkpoint = 1
            
            ;++++++++++++++++++++++++++++++++++++++++++++++++++++
            ;+ Si on est en X à + ou - 5 px et + ou - 5 px en Y alors la condition
            ;+ est bonne et donc on passe au prochain checkpoint
            ;++++++++++++++++++++++++++++++++++++++++++++++++++++
            ;If Int(Arrow\x) - 5 <= Target(1)\x  And Int(Arrow\x) + 5 >= Target(1)\x    And  Int(Arrow\y) - 5 <= Target(1)\y  And Int(Arrow\y) + 5 >= Target(1)\y
            If Target(1)\x >=  Int(Arrow\x) - 5 And Target(1)\x <=  Int(Arrow\x) + 5   And  Target(1)\y >= Int(Arrow\y) - 5  And Target(1)\y <= Int(Arrow\y) + 5
                  ; Delay(2000)
                  checkpoint = 2
                  
            Else
                  Circle(Target(1)\x, Target(1)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(1)\x - 10, Target(1)\y + 10, "Checkpoint 1")
                  track_SmoothPoint(@Arrow,@Target(1), #turnspeed)
            EndIf
      EndIf
      
      
      
      ; Le 2ème checkpoint à atteindre
      If checkpoint = 2
            
            ;If Int(Arrow\x) - 5 <= Target(2)\x  And Int(Arrow\x) + 5 >= Target(2)\x    And  Int(Arrow\y) - 5 <= Target(2)\y  And Int(Arrow\y) + 5 >= Target(2)\y
            If Target(2)\x >=  Int(Arrow\x) - 5 And Target(2)\x <=  Int(Arrow\x) + 5 And Target(2)\y >= Int(Arrow\y) - 5 And Target(2)\y <= Int(Arrow\y) + 5
                  ; Delay(2000)
                  checkpoint = 3
            Else
                  Circle(Target(2)\x, Target(2)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(2)\x - 10, Target(2)\y + 10, "Checkpoint 2")
                  track_SmoothPoint(@Arrow,@Target(2), #turnspeed)
            EndIf
            
      EndIf
      
      
      
      If checkpoint = 3
            
            ;If Int(Arrow\x) - 5 <= Target(3)\x  And Int(Arrow\x) + 5 >= Target(3)\x    And  Int(Arrow\y) - 5 <= Target(3)\y  And Int(Arrow\y) + 5 >= Target(3)\y
            If Target(3)\x >=  Int(Arrow\x) - 5 And Target(3)\x <=  Int(Arrow\x) + 5   And  Target(3)\y >= Int(Arrow\y) - 5  And Target(3)\y <= Int(Arrow\y) + 5
                  ;If Int(Arrow\x) = Target(1)\x Or Int(Arrow\y) = Target(1)\y 
                  ; Delay(2000)
                  checkpoint = 1
            Else
                  Circle(Target(3)\x, Target(3)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(3)\x - 10, Target(3)\y + 10, "Checkpoint 3")
                  track_SmoothPoint(@Arrow,@Target(3), #turnspeed)
            EndIf
            
      EndIf    
      
      
      
      
      If checkpoint = 4
            
            ;If Int(Arrow\x) - 5 <= Target(4)\x  And Int(Arrow\x) + 5 >= Target(4)\x    And  Int(Arrow\y) - 5 <= Target(4)\y  And Int(Arrow\y) + 5 >= Target(4)\y
            If Target(4)\x >=  Int(Arrow\x) - 5 And Target(4)\x <=  Int(Arrow\x) + 5   And  Target(4)\y >= Int(Arrow\y) - 5  And Target(4)\y <= Int(Arrow\y) + 5
                  ; Delay(2000)
                  checkpoint = 1
            Else
                  Circle(Target(4)\x, Target(4)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(4)\x - 10, Target(4)\y + 10, "Checkpoint 4")
                  track_SmoothPoint(@Arrow,@Target(4), #turnspeed)
            EndIf
      EndIf                   
      
      
      DrawText(Arrow\x - 70, Arrow\y + 10, "{"+ Str(Target(checkpoint)\x) +" | "+ Str(Int(Arrow\x)) +", "+ Str(Target(checkpoint)\y) +" | "+ Str(Int(Arrow\y)) +"}" )
      
      
      StopDrawing()
      
      ;++++++++++++++++++++++++++++++++++++++++++++++++++++
      ;+ La voiture se dirige vers le chemin du checkpoint à la vitesse 1
      ;++++++++++++++++++++++++++++++++++++++++++++++++++++
      Arrow\x + 1 *Cos(Arrow\Angle*#PI/180)
      Arrow\y + 1 *Sin(Arrow\Angle*#PI/180)
      
      ;       Define vitesse.b 
      ;       vitesse = Random(3)
      ;       Arrow\x + vitesse *Cos(Arrow\Angle*#PI/180)
      ;       Arrow\y + vitesse *Sin(Arrow\Angle*#PI/180)
      
      
      ; Affichage des sprites
      If Start3D()
            ; Affichage Car IA
            DisplaySprite3D(#Voiture3D_IA, Arrow\x - 8, Arrow\y - 8)
            RotateSprite3D(#Voiture3D_IA, Arrow\Angle, 0)
            
            Stop3D()
            
      EndIf
      
      
      If KeyboardPushed(#PB_Key_Escape)<>#Null : Quit=1 : EndIf
      FlipBuffers()
Until Quit=1
End



Procedure.f curveangle(newangle.f,oldangle.f,increments.f)
      If increments > 1
            If (oldangle + 360) - newangle < newangle - oldangle
                  oldangle = 360 + oldangle 
            EndIf
            If (newangle + 360) - oldangle < oldangle - newangle
                  newangle = 360 + newangle
            EndIf
            oldangle = oldangle - (oldangle - newangle) / increments
      EndIf
      
      If increments <= 1
            ;Debug "newangle : "+ StrF(newangle)
            ProcedureReturn newangle
            
      EndIf
      
      ;Debug "oldangle : "+ StrF(oldangle)
      ProcedureReturn oldangle
EndProcedure


Procedure.f ReturnDegAngle(x1.f,y1.f,x2.f,y2.f) ; DEGREE
      Protected A.f, b.f, c.f, Angle.f
      A.f = x1-x2
      b.f = y1-y2
      c.f = -Sqr(A*A+b*b)
      Angle.f = ACos(A / c) * 180 / #PI
      If y1 < y2 : Angle = 360 - Angle : EndIf
      ProcedureReturn Abs(Angle - 360)
EndProcedure


Procedure track_SmoothPoint(*A.ENTITY,*B.ENTITY, turnspeed.f=1.0)
      Protected AngDif.f, temp_yaw.f
      AngDif = ReturnDegAngle(*A\x,*A\y,*B\x,*B\y)
      temp_yaw.f = curveangle(AngDif, *A\Angle, turnspeed)
      *A\Angle = temp_yaw
      ;*A\Angle = AngDif
EndProcedure
Le but de ce code :
Faire une petite IA pour un jeu de voiture.
La voiture se déplacera de checkpoint en checkpoint.
INFO : Le checkpoint 4 n'est pas utilisé, on passe du 3ème au 1er

1) 1ère question un peu honteuse.
A force d'essais pour arriver à quelque chose qui fonctionne, j'en suis arrivé à ne plus savoir quoi mettre à gauche et à droite dans le if.
Surtout que les 2 solutions au final fonctionnent
Si on veut savoir si on est à + ou - 5 px en X, j'ai donc le choix entre :
If Target(1)\x >= Int(Arrow\x) - 5 And Target(1)\x <= Int(Arrow\x) + 5
ou
If Int(Arrow\x) - 5 <= Target(1)\x And Int(Arrow\x) + 5 >= Target(1)\x

Target(1)\x est la valeur fixe, ici de 500 et Target(1)\x la valeur qui varie.
Donc quel est la solution la plus logique.
J'ai laissé l'autre solution en commentaire.

2) Est ce qu'il y aurait une technique plus subtile pour vérifier que l'on à bien atteint le checkpoint
Parce qu'actuellement si je mets une valeur supérieure à + ou - 5px la voiture tourne trop tôt et si l'on vire le + ou - 5px la condition n'est pas remplie et la voiture ne va plus au prochain checkpoint.

Bref, ce n'est pas très fiable comme vérification.

3) Lors du passage aux différents checkpoints la 1ère fois, tout va bien, mais au second tour lorsque la voiture atteint de nouveau le checkpoint 1, la voiture fait un tour sur elle même.
J'aurais voulu savoir d'où venait le problème, mais je suis nul en math.
J'aurais voulu que la voiture prenne toujours le checkpoint dans le sens des aiguilles d'une montre, ce qui conviendrait pour un circuit en rond, mais je viens de penser qu'il pourrait y avoir un problème avec un circuit en forme de "T" où il y aurait des virages à droite mais aussi à gauche.

Je me dis qu'en plus des coordonnées du checkpoint, je pourrais ajouter l'info sur le type de virage, genre D, G, ou TD (Droite, Gauche ou ToutDroit lorsque qu'il faut dévier de quelques degrés)

Bref, est-ce qu'il y aurait un matheux charitable qui pourrait solutionner la chose.

Si on modifie la procédure "track_SmoothPoint()" comme ceci, on a un pivot basique :

Code : Tout sélectionner

Procedure track_SmoothPoint(*A.ENTITY,*B.ENTITY, turnspeed.f=1.0)
      Protected AngDif.f, temp_yaw.f
      AngDif = ReturnDegAngle(*A\x,*A\y,*B\x,*B\y)
      temp_yaw.f = curveangle(AngDif, *A\Angle, turnspeed)
      ;*A\Angle = temp_yaw
      *A\Angle = AngDif
EndProcedure
Donc la fonction curveangle() ajoute un effet sympa, mais qui pose problème.

Bye.
Dernière modification par Geo Trouvpatou le lun. 15/août/2011 16:01, modifié 1 fois.
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: if..else..endif et trigonométrie code de Cpl.Bator

Message par G-Rom »

Code : Tout sélectionner

;-Structures
; Structure VECTOR2
;       x.f
;       y.f
; EndStructure

Structure ENTITY
      ;Position.VECTOR2
      x.f
      y.f
      Angle.f
EndStructure
Pourquoi tu as commenté la partie vecteur ? c'est la plus importante pour ajouté des fonctionnalité ;)
Voila un code qui te dis si 2 vecteurs sont près l'un de l'autre :

Code : Tout sélectionner

Structure VECTOR2
      x.f
      y.f
EndStructure

Structure ENTITY
      Position.VECTOR2
      x.f
      y.f
      Angle.f
EndStructure

Procedure VECTOR2_Set(*a.VECTOR2,x.f, y.f)
  *a\x = x
  *a\y = y
EndProcedure

Procedure.f VECTOR2_Length(*a.VECTOR2)
  ProcedureReturn  Sqr(*a\x * *a\x + *a\y * *a\y)
EndProcedure

Procedure.f VECTOR2_SquaredLength(*a.VECTOR2)
  ProcedureReturn  *a\x * *a\x + *a\y * *a\y 
EndProcedure

Procedure VECTOR2_SquaredDistance(*a.VECTOR2, *b.VECTOR2)
  R.VECTOR2 
  R\x = *a\x - *b\x
  R\y = *a\y - *b\y
  ProcedureReturn VECTOR2_SquaredLength(@R)
EndProcedure


Procedure.b VECTOR2_PositionCloses(*a.VECTOR2, *b.VECTOR2, tolerance.f = 1e-03f )
  If VECTOR2_SquaredDistance(*a,*b) <= (VECTOR2_SquaredLength(*a) + VECTOR2_SquaredLength(*b)) * tolerance
    ProcedureReturn #True 
  Else
    ProcedureReturn #False
  EndIf 
EndProcedure
    


PosA.VECTOR2
PosB.VECTOR2

VECTOR2_Set(@PosA,10,10) ; il sont près , mais pas égal
VECTOR2_Set(@PosB,11,11)
Debug VECTOR2_PositionCloses(@PosA, @PosB) ; Retourne 0 , ils ne sont pas encore assez près 

VECTOR2_Set(@PosB,10.5,10.5) ; on rapproche le 2° vecteur
Debug VECTOR2_PositionCloses(@PosA, @PosB) ; Retourne 1 , ils sont assez près
Geo Trouvpatou
Messages : 471
Inscription : dim. 23/déc./2007 18:10

Re: if..else..endif et trigonométrie code de Cpl.Bator

Message par Geo Trouvpatou »

Salut.
G-Rom a écrit :Pourquoi tu as commenté la partie vecteur ? c'est la plus importante pour ajouté des fonctionnalité ;)
Ben, comme précisé dans mon message : "Je suis nul en math".
Donc j'ai voulu simplifier au maximum le code :D.

Ton message est pour moi un peu comme du chinois. Mais j'en ai déduis que tu répondais à ma 2ème question : "2) Est ce qu'il y aurait une technique plus subtile pour vérifier que l'on à bien atteint le checkpoint"
Dans le code que tu as mis, j'imagine que l'on indique le point de départ et d'arrivée avec "VECTOR2_Set()" et que la vérif que le point est bien atteint se fait avec "VECTOR2_PositionCloses()".

Mais après plusieurs essais, j'ai trouvé quelque chose qui clochait.
En mettant ces valeurs :
VECTOR2_Set(@PosA,10,320)
VECTOR2_Set(@PosB,14,334)
Debug VECTOR2_PositionCloses(@PosA, @PosB)
Cela me retourne que le point serait atteint, alors que c'est loin d'être le cas.
Cela vient peut-être de moi, parce que je n'ai pas compris la subtilité du paramètre : "tolerance.f".

Dés le départ pour essayer de comprendre au moins 1% de ton code, j'ai dû faire des recherches sur internet.
Par rapport à ce que tu avais dis, j'ai cherché : "Comment savoir si 2 vecteurs sont près l'un de l'autre" et je suis tombé sur cette page : http://www.cmath.fr/3eme/vecteurs/cours.php
Et en milieu de page, je vois : "Distance entre 2 points dans un repère :"
Je convertis le truc comme ça :

Code : Tout sélectionner

Procedure.f DistanceEntre2Points(ax.f, ay.f, bx.f, by.f)
ProcedureReturn Sqr(Pow((bx - ax), 2) + Pow((by - ay), 2))
EndProcedure
Et là génial, cela fonctionne à merveille.
Voici le nouveau code :

Code : Tout sélectionner

; Algo tiré d'un code de Cpl.Bator : http://www.game-corp.net/topic-744-purebasic-poursuite-d-039-un-point-par-un-autre.html

EnableExplicit
Enumeration
      #Voiture
      #Voiture3D_IA
EndEnumeration

#SW = 640
#SH = 480
UsePNGImageDecoder()

InitSprite() : InitKeyboard() : InitMouse()
If InitSprite3D() = 0
      MessageRequester("Erreur", "La librairie Sprite3D n'a pas pu être initialisée", 0)
      End
EndIf
;OpenWindow(0, 0, 0, 640, 480, "Un écran dans une fenêtre...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
;OpenWindowedScreen(WindowID(0), 0, 0, #SW, #SH, 0, 0, 0)

OpenScreen(#SW, #SH, 32, "")

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
      Structure point
            x.f
            y.f
      EndStructure
CompilerEndIf


;-Structures
Structure VECTOR2
      x.f
      y.f
EndStructure

Structure ENTITY
      Position.VECTOR2
      x.f
      y.f
      Angle.f
EndStructure


;-Declarations des fonctions
Declare.f curveangle(newangle.f,oldangle.f,increments.f)
Declare.f ReturnDegAngle(x1.f,y1.f,x2.f,y2.f)
Declare track_SmoothPoint(*A.ENTITY,*B.ENTITY, turnspeed.f=1.0)
Declare .f DistanceEntre2Points(ax.f, ay.f, bx.f, by.f)
#turnspeed = 4

; ************************************************************************************
; Voiture.
; Ses coordonnées pour la position de départ
Global Voiture.ENTITY
Voiture\x = 100
Voiture\y = 250
Voiture\Angle = 0

; Tableau pour stocker les différents checkpoint à atteindre
Global Dim Target.ENTITY(10)

Target(1)\x = 325
Target(1)\y = 90

Target(2)\x = 470
 Target(2)\y = 106

Target(3)\x = 531
Target(3)\y = 134

Target(4)\x = 548
Target(4)\y = 240

Target(5)\x = 526
Target(5)\y = 340

Target(6)\x = 480
Target(6)\y = 380

Target(7)\x = 412
Target(7)\y = 400

Target(8)\x = 180
Target(8)\y = 360

Target(9)\x = 52
Target(9)\y = 260

Target(10)\x = 130
Target(10)\y = 125

Global checkpoint = 1
Global Quit

;LoadSprite(#Voiture, "voitureFin.png", #PB_Sprite_Texture)

; Super voiture de sport rouge dont on ne citera pas la marque.
CreateSprite(#Voiture, 16, 16, #PB_Sprite_Texture)
StartDrawing(SpriteOutput(#Voiture))
Box(3, 0, 16, 10, RGB(255, 0, 0))
Box(12, 4, 4, 2, RGB(255, 255, 255))
StopDrawing()

; Création du Sprite 3d
CreateSprite3D(#Voiture3D_IA, #Voiture)

; Ci-dessous si on utilise le programme dans le mode fenêtré.
;ReleaseMouse(1)

Repeat
      ClearScreen(0)
      ExamineKeyboard()
      ExamineMouse()
      Define Mx = MouseX()
Define My = MouseY()
      
      StartDrawing(ScreenOutput())
      
      ; Affichage de tous les points du circuit à atteindre.
      Circle(Target(1)\x, Target(1)\y, 2, RGB(0, 255, 255))
      Circle(Target(2)\x, Target(2)\y, 2, RGB(0, 255, 255))
      Circle(Target(3)\x, Target(3)\y, 2, RGB(0, 255, 255))
      Circle(Target(4)\x, Target(4)\y, 2, RGB(0, 255, 255))
      Circle(Target(5)\x, Target(5)\y, 2, RGB(0, 255, 255))
      Circle(Target(6)\x, Target(6)\y, 2, RGB(0, 255, 255))
      Circle(Target(7)\x, Target(7)\y, 2, RGB(0, 255, 255))
      Circle(Target(8)\x, Target(8)\y, 2, RGB(0, 255, 255))
      Circle(Target(9)\x, Target(9)\y, 2, RGB(0, 255, 255))
      Circle(Target(10)\x, Target(10)\y, 2, RGB(0, 255, 255))
      
      ; Coordonnées du pointeur de la souris.
      ;DrawText(Mx - 70, My + 10, "{"+ Str(Mx) +", "+ Str(My) +"}" )
      
      
      ; Le 1er checkpoint à atteindre
      If checkpoint = 1
            
            ;++++++++++++++++++++++++++++++++++++++++++++++++++++
            ;+ Si on est en X à + ou - 5 px et + ou - 5 px en Y alors la condition
            ;+ est bonne et donc on passe au prochain checkpoint
            
            ;+ Avec la nouvelle Procedure "DistanceEntre2Points()" on doit juste vérifier 
            ;+ que la distance entre le point de départ (Voiture) et la cible (Checkpoint)
            ;+ doit être inférieur à 5 px. C'est plus fiable que l'ancienne vérif.
            ;++++++++++++++++++++++++++++++++++++++++++++++++++++
            ;If Int(Voiture\x) - 5 <= Target(1)\x  And Int(Voiture\x) + 5 >= Target(1)\x    And  Int(Voiture\y) - 5 <= Target(1)\y  And Int(Voiture\y) + 5 >= Target(1)\y
            ;If Target(1)\x >=  Int(Voiture\x) - 5 And Target(1)\x <=  Int(Voiture\x) + 5   And  Target(1)\y >= Int(Voiture\y) - 5  And Target(1)\y <= Int(Voiture\y) + 5
            If DistanceEntre2Points(Voiture\x, Voiture\y, Target(1)\x, Target(1)\y) < 5
            ; Delay(2000)
                  checkpoint = 2
                  
            Else
                  Circle(Target(1)\x, Target(1)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(1)\x - 10, Target(1)\y + 10, "Checkpoint 1")
                  track_SmoothPoint(@Voiture, @Target(1), #turnspeed)
            EndIf
      EndIf
      
      
      ; Le 2ème checkpoint à atteindre
      If checkpoint = 2
            If DistanceEntre2Points(Voiture\x, Voiture\y, Target(2)\x, Target(2)\y) < 5      
                  ; Delay(2000)
                  checkpoint = 3
            Else
                  Circle(Target(2)\x, Target(2)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(2)\x - 10, Target(2)\y + 10, "Checkpoint 2")
                  track_SmoothPoint(@Voiture,@Target(2), #turnspeed)
            EndIf
            
      EndIf
      
      
      If checkpoint = 3
            If DistanceEntre2Points(Voiture\x, Voiture\y, Target(3)\x, Target(3)\y) < 5
                  ; Delay(2000)
                  checkpoint = 4
            Else
                  Circle(Target(3)\x, Target(3)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(3)\x - 10, Target(3)\y + 10, "Checkpoint 3")
                  track_SmoothPoint(@Voiture,@Target(3), #turnspeed)
            EndIf
            
      EndIf    
      
      
      If checkpoint = 4
            If DistanceEntre2Points(Voiture\x, Voiture\y, Target(4)\x, Target(4)\y) < 5   
                  ; Delay(2000)
                  checkpoint = 5
            Else
                  Circle(Target(4)\x, Target(4)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(4)\x - 10, Target(4)\y + 10, "Checkpoint 4")
                  track_SmoothPoint(@Voiture,@Target(4), #turnspeed)
            EndIf
      EndIf      
      
      
            If checkpoint = 5
           If DistanceEntre2Points(Voiture\x, Voiture\y, Target(5)\x, Target(5)\y) < 5   
                  ; Delay(2000)
                  checkpoint = 6
            Else
                  Circle(Target(5)\x, Target(5)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(5)\x - 10, Target(5)\y + 10, "Checkpoint 5")
                  track_SmoothPoint(@Voiture,@Target(5), #turnspeed)
            EndIf
      EndIf                   
      
      
            If checkpoint = 6
            If DistanceEntre2Points(Voiture\x, Voiture\y, Target(6)\x, Target(6)\y) < 5   
                  ; Delay(2000)
                  checkpoint = 7
            Else
                  Circle(Target(6)\x, Target(6)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(6)\x - 10, Target(6)\y + 10, "Checkpoint 6")
                  track_SmoothPoint(@Voiture,@Target(6), #turnspeed)
            EndIf
      EndIf     
      
      
                  If checkpoint = 7
             If DistanceEntre2Points(Voiture\x, Voiture\y, Target(7)\x, Target(7)\y) < 5   
                  ; Delay(2000)
                  checkpoint = 8
            Else
                  Circle(Target(7)\x, Target(7)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(7)\x - 10, Target(7)\y + 10, "Checkpoint 7")
                  track_SmoothPoint(@Voiture,@Target(7), #turnspeed)
            EndIf
      EndIf     
      
      
                        If checkpoint = 8
            If DistanceEntre2Points(Voiture\x, Voiture\y, Target(8)\x, Target(8)\y) < 5   
                  ; Delay(2000)
                  checkpoint = 9
            Else
                  Circle(Target(8)\x, Target(8)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(8)\x - 10, Target(8)\y + 10, "Checkpoint 8")
                  track_SmoothPoint(@Voiture,@Target(8), #turnspeed)
            EndIf
      EndIf     
      
      
                             If checkpoint = 9
            If DistanceEntre2Points(Voiture\x, Voiture\y, Target(9)\x, Target(9)\y) < 5   
                  ; Delay(2000)
                  checkpoint = 10
            Else
                  Circle(Target(9)\x, Target(9)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(9)\x - 10, Target(9)\y + 10, "Checkpoint 9")
                  track_SmoothPoint(@Voiture,@Target(9), #turnspeed)
            EndIf
      EndIf     
      
                             If checkpoint = 10
            If DistanceEntre2Points(Voiture\x, Voiture\y, Target(10)\x, Target(10)\y) < 5   
                  ; Delay(2000)
                  checkpoint = 1
            Else
                  Circle(Target(10)\x, Target(10)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(10)\x - 10, Target(10)\y + 10, "Checkpoint 10")
                  track_SmoothPoint(@Voiture,@Target(10), #turnspeed)
            EndIf
      EndIf     
      
      
      DrawText(Voiture\x - 70, Voiture\y + 10, "{"+ Str(Target(checkpoint)\x) +" | "+ Str(Int(Voiture\x)) +", "+ Str(Target(checkpoint)\y) +" | "+ Str(Int(Voiture\y)) +"}" )
      
      
      StopDrawing()
      
      ;++++++++++++++++++++++++++++++++++++++++++++++++++++
      ;+ La voiture se dirige vers le chemin du checkpoint à la vitesse 2.5
      ;++++++++++++++++++++++++++++++++++++++++++++++++++++
      Voiture\x + 2.5 *Cos(Voiture\Angle*#PI/180)
      Voiture\y + 2.5 *Sin(Voiture\Angle*#PI/180)
      
;             Define vitesse.b 
;             vitesse = Random(3)
;             Voiture\x + vitesse *Cos(Voiture\Angle*#PI/180)
;             Voiture\y + vitesse *Sin(Voiture\Angle*#PI/180)
      
      
      ; Affichage des sprites
      If Start3D()
            ; Affichage Car IA
            DisplaySprite3D(#Voiture3D_IA, Voiture\x - 8, Voiture\y - 8)
            RotateSprite3D(#Voiture3D_IA, Voiture\Angle, 0)
            
            Stop3D()
            
      EndIf
      
      
      If KeyboardPushed(#PB_Key_Escape)<>#Null : Quit=1 : EndIf
      FlipBuffers()
Until Quit=1
End



Procedure.f curveangle(newangle.f,oldangle.f,increments.f)
      If increments > 1
            If (oldangle + 360) - newangle < newangle - oldangle
                  oldangle = 360 + oldangle 
            EndIf
            If (newangle + 360) - oldangle < oldangle - newangle
                  newangle = 360 + newangle
            EndIf
            oldangle = oldangle - (oldangle - newangle) / increments
      EndIf
      
      If increments <= 1
            ProcedureReturn newangle
      EndIf

      ProcedureReturn oldangle
EndProcedure


Procedure.f ReturnDegAngle(x1.f,y1.f,x2.f,y2.f) ; DEGREE
      Protected A.f, b.f, c.f, Angle.f
      A.f = x1-x2
      b.f = y1-y2
      c.f = -Sqr(A*A+b*b)
      Angle.f = ACos(A / c) * 180 / #PI
      If y1 < y2 : Angle = 360 - Angle : EndIf
      ProcedureReturn Abs(Angle - 360)
EndProcedure


Procedure track_SmoothPoint(*A.ENTITY,*B.ENTITY, turnspeed.f=1.0)
      Protected AngDif.f, temp_yaw.f

      AngDif = ReturnDegAngle(*A\x,*A\y,*B\x,*B\y)
      ; Debug "AngDif : "+ StrF(AngDif)
      temp_yaw.f = curveangle(AngDif, *A\Angle, turnspeed)
      ; Debug "temp_yaw : "+ StrF(temp_yaw)
         *A\Angle = temp_yaw
      ;*A\Angle = AngDif
EndProcedure

Procedure.f DistanceEntre2Points(ax.f, ay.f, bx.f, by.f)
ProcedureReturn Sqr(Pow((bx - ax), 2) + Pow((by - ay), 2))
EndProcedure
Maintenant le problème de la 3ème question de mon 1er post subsiste :
"3) Lors du passage aux différents checkpoints la 1ère fois, tout va bien, mais au second tour lorsque la voiture atteint de nouveau le checkpoint 1, la voiture fait un tour sur elle même.
J'aurais voulu savoir d'où venait le problème, mais je suis nul en math.
J'aurais voulu que la voiture prenne toujours le checkpoint dans le sens des aiguilles d'une montre, ce qui conviendrait pour un circuit en rond, mais je viens de penser qu'il pourrait y avoir un problème avec un circuit en forme de "T" où il y aurait des virages à droite mais aussi à gauche.

Je me dis qu'en plus des coordonnées du checkpoint, je pourrais ajouter l'info sur le type de virage, genre D, G, ou TD (Droite, Gauche ou ToutDroit lorsque qu'il faut dévier de quelques degrés)
"

Au pire je supprimerai l'adoucissement de l'angle et augmenterai le nombre de checkpoints pour que le changement de trajectoire soit moins brutal.

Je le répète, étant nul en math, je cherche les solutions les plus simplettes qui soient.

Bye.
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: if..else..endif et trigonométrie code de Cpl.Bator

Message par G-Rom »

Ton message est pour moi un peu comme du chinois.
:?
Mais après plusieurs essais, j'ai trouvé quelque chose qui clochait.
En mettant ces valeurs :
VECTOR2_Set(@PosA,10,320)
VECTOR2_Set(@PosB,14,334)
Debug VECTOR2_PositionCloses(@PosA, @PosB)
Cela me retourne que le point serait atteint, alors que c'est loin d'être le cas.
J'ai du me piner quelque part , j'ai codé ca pour toi vite fait.
Dés le départ pour essayer de comprendre au moins 1% de ton code, j'ai dû faire des recherches sur internet.
Par rapport à ce que tu avais dis, j'ai cherché : "Comment savoir si 2 vecteurs sont près l'un de l'autre" et je suis tombé sur cette page : http://www.cmath.fr/3eme/vecteurs/cours.php
Et en milieu de page, je vois : "Distance entre 2 points dans un repère :"
Je convertis le truc comme ça :
Ton code converti est dans la doc de PB :D

la voiture fait un tour sur elle même.
Le problème est solvable en prenant l'angle le plus court à parcourir.


Sinon , pour un jeu de voiture , je ne me baserais pas sur des points comme tu le fait , mais sur des splines, ca te permet d'avoir des angles correct , pas de demis tour donc.
Geo Trouvpatou
Messages : 471
Inscription : dim. 23/déc./2007 18:10

Re: if..else..endif et trigonométrie code de Cpl.Bator

Message par Geo Trouvpatou »

Salut.
G-Rom a écrit :J'ai du me piner quelque part
Ce ne serait pas là :

Code : Tout sélectionner

Procedure.f VECTOR2_Length(*a.VECTOR2)
      ProcedureReturn  Sqr(*a\x * *a\x + *a\y * *a\y)
EndProcedure
J'avais supposé que c'était la même chose que ma fonction, mais le résultat était différent.
G-Rom a écrit :Ton code converti est dans la doc de PB :D
Distance entre deux points

(x1|y1) = coordonnées XY du point n°1
(x2|y2) = coordonnées XY du point n°2
a = Distance entre les points

a = SQR((x1-x2)^2 + (y1-y2)^2)
J'suis dèg :| , mais bon, content de moi quand même :lol:.
G-Rom a écrit :Le problème est solvable en prenant l'angle le plus court à parcourir.
Lorsque le prog démarre l'angle pour rejoindre le 1er checkpoint est de 333° ensuite pour aller au n°2 il y a 70°, je vais essayer de trouver ça sur internet.

G-Rom a écrit :Sinon , pour un jeu de voiture , je ne me baserais pas sur des points comme tu le fait , mais sur des splines, ca te permet d'avoir des angles correct , pas de demis tour donc.
Si, les calculs se font uniquement à base des 4 opérations standards, alors ça sera de mon niveau, sinon je coule :mrgreen:

Merci.
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: if..else..endif et trigonométrie code de Cpl.Bator

Message par G-Rom »

heu , encore plus simple , un angle va de 0 à 360 :
t'évite les demis tours avec ca en plus :

Code : Tout sélectionner

      If Arrow\Angle => 360
         Arrow\Angle = 0
      EndIf 
      
      If Arrow\Angle < 0
         Arrow\Angle = 359
      EndIf 

@++
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: if..else..endif et trigonométrie code de Cpl.Bator

Message par graph100 »

pourquoi tu n'utilises pas les modulo ?

Code : Tout sélectionner

angle = angle % 360
tu auras toujours une valeur entre 0 et 360
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: if..else..endif et trigonométrie code de Cpl.Bator

Message par G-Rom »

graph100 a écrit :pourquoi tu n'utilises pas les modulo ?

Code : Tout sélectionner

angle = angle % 360
tu auras toujours une valeur entre 0 et 360
pas avec un float ;)
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: if..else..endif et trigonométrie code de Cpl.Bator

Message par graph100 »

bien vu ;) mais c'est dommage :s
_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Geo Trouvpatou
Messages : 471
Inscription : dim. 23/déc./2007 18:10

Re: if..else..endif et trigonométrie code de Cpl.Bator

Message par Geo Trouvpatou »

G-Rom ta solution résout le problème, mais étrangement les arrondis sont beaux dans le sens horaire et le sont moins, dans le sens anti-horaire.
Assez flagrant sur le checkpoint 4 où le changement de position est vraiment brutal :

Code : Tout sélectionner

; Algo tiré d'un code de Cpl.Bator : http://www.game-corp.net/topic-744-purebasic-poursuite-d-039-un-point-par-un-autre.html

EnableExplicit
Enumeration
      #Voiture
      #Voiture3D_IA
EndEnumeration

#SW = 640
#SH = 480
UsePNGImageDecoder()

InitSprite() : InitKeyboard() : InitMouse()
If InitSprite3D() = 0
      MessageRequester("Erreur", "La librairie Sprite3D n'a pas pu être initialisée", 0)
      End
EndIf
;OpenWindow(0, 0, 0, 640, 480, "Un écran dans une fenêtre...", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
;OpenWindowedScreen(WindowID(0), 0, 0, #SW, #SH, 0, 0, 0)

OpenScreen(#SW, #SH, 32, "")

CompilerIf #PB_Compiler_OS = #PB_OS_Linux
      Structure point
            x.f
            y.f
      EndStructure
CompilerEndIf


;-Structures
Structure VECTOR2
      x.f
      y.f
EndStructure

Structure ENTITY
      Position.VECTOR2
      x.f
      y.f
      Angle.f
EndStructure


;-Declarations des fonctions
Declare.f curveangle(newangle.f,oldangle.f,increments.f)
Declare.f ReturnDegAngle(x1.f,y1.f,x2.f,y2.f)
Declare track_SmoothPoint(*A.ENTITY,*B.ENTITY, turnspeed.f=1.0)
Declare .f DistanceEntre2Points(ax.f, ay.f, bx.f, by.f)
#turnspeed = 4

; ************************************************************************************
; Voiture.
; Ses coordonnées pour la position de départ
Global Voiture.ENTITY
Voiture\x = 100
Voiture\y = 250
Voiture\Angle = 0

; Tableau pour stocker les différents checkpoint à atteindre
Global Dim Target.ENTITY(4)


; En 8
Target(1)\x = 300
Target(1)\y = 100

Target(2)\x = 300
 Target(2)\y = 280

Target(3)\x = 100
Target(3)\y = 100

Target(4)\x = 100
Target(4)\y = 280


Global checkpoint = 1
Global Quit

;LoadSprite(#Voiture, "voitureFin.png", #PB_Sprite_Texture)

; Super voiture de sport rouge dont on ne citera pas la marque.
CreateSprite(#Voiture, 16, 16, #PB_Sprite_Texture)
StartDrawing(SpriteOutput(#Voiture))
Box(3, 0, 16, 10, RGB(255, 0, 0))
Box(12, 4, 4, 2, RGB(255, 255, 255))
StopDrawing()

; Création du Sprite 3d
CreateSprite3D(#Voiture3D_IA, #Voiture)

; Ci-dessous si on utilise le programme dans le mode fenêtré.
;ReleaseMouse(1)

Repeat
      ClearScreen(0)
      ExamineKeyboard()
      ExamineMouse()
      ;Define Mx = MouseX()
      ;Define My = MouseY()
      
      StartDrawing(ScreenOutput())
      
      ; Affichage de tous les points du circuit à atteindre.
      Circle(Target(1)\x, Target(1)\y, 2, RGB(0, 255, 255))
      Circle(Target(2)\x, Target(2)\y, 2, RGB(0, 255, 255))
      Circle(Target(3)\x, Target(3)\y, 2, RGB(0, 255, 255))
      Circle(Target(4)\x, Target(4)\y, 2, RGB(0, 255, 255))
      
      ; Coordonnées du pointeur de la souris.
      ;DrawText(Mx - 70, My + 10, "{"+ Str(Mx) +", "+ Str(My) +"}" )
      
      
      ; Le 1er checkpoint à atteindre
      If checkpoint = 1
          If DistanceEntre2Points(Voiture\x, Voiture\y, Target(1)\x, Target(1)\y) < 5
            ; Delay(2000)
                  checkpoint = 2
                  
            Else
                  Circle(Target(1)\x, Target(1)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(1)\x - 10, Target(1)\y + 10, "Checkpoint 1")
                  track_SmoothPoint(@Voiture, @Target(1), #turnspeed)
            EndIf
      EndIf
      
      
      ; Le 2ème checkpoint à atteindre
      If checkpoint = 2
            If DistanceEntre2Points(Voiture\x, Voiture\y, Target(2)\x, Target(2)\y) < 5      
                  ; Delay(2000)
                  checkpoint = 3
            Else
                  Circle(Target(2)\x, Target(2)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(2)\x - 10, Target(2)\y + 10, "Checkpoint 2")
                  track_SmoothPoint(@Voiture,@Target(2), #turnspeed)
            EndIf
            
      EndIf
      
      
      If checkpoint = 3
            If DistanceEntre2Points(Voiture\x, Voiture\y, Target(3)\x, Target(3)\y) < 5
                  ; Delay(2000)
                  checkpoint = 4
            Else
                  Circle(Target(3)\x, Target(3)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(3)\x - 10, Target(3)\y + 10, "Checkpoint 3")
                  track_SmoothPoint(@Voiture,@Target(3), #turnspeed)
            EndIf
            
      EndIf    
      
      
      If checkpoint = 4
            If DistanceEntre2Points(Voiture\x, Voiture\y, Target(4)\x, Target(4)\y) < 5   
                  ; Delay(2000)
                  checkpoint = 1
            Else
                  Circle(Target(4)\x, Target(4)\y, 2, RGB(255, 255, 255))
                  DrawText(Target(4)\x - 10, Target(4)\y + 10, "Checkpoint 4")
                  track_SmoothPoint(@Voiture,@Target(4), #turnspeed)
            EndIf
      EndIf      
      

      DrawText(Voiture\x - 70, Voiture\y + 10, "{"+ Str(Target(checkpoint)\x) +" | "+ Str(Int(Voiture\x)) +", "+ Str(Target(checkpoint)\y) +" | "+ Str(Int(Voiture\y)) +"}" )
      
      
      StopDrawing()
      
      ;++++++++++++++++++++++++++++++++++++++++++++++++++++
      ;+ La voiture se dirige vers le chemin du checkpoint à la vitesse 2.5
      ;++++++++++++++++++++++++++++++++++++++++++++++++++++
      Voiture\x + 1.5 *Cos(Voiture\Angle*#PI/180)
      Voiture\y + 1.5 *Sin(Voiture\Angle*#PI/180)
      
;             Define vitesse.b 
;             vitesse = Random(3)
;             Voiture\x + vitesse *Cos(Voiture\Angle*#PI/180)
;             Voiture\y + vitesse *Sin(Voiture\Angle*#PI/180)
      
      
      ; Affichage des sprites
      If Start3D()
            If Voiture\Angle => 360
                  Voiture\Angle = 0
            EndIf
            
            If Voiture\Angle < 0
                  Voiture\Angle = 359
            EndIf 
   
            ; Affichage Car IA
            DisplaySprite3D(#Voiture3D_IA, Voiture\x - 8, Voiture\y - 8)
            RotateSprite3D(#Voiture3D_IA, Voiture\Angle, 0)
            
            Stop3D()
            
      EndIf
      
      
      If KeyboardPushed(#PB_Key_Escape)<>#Null : Quit=1 : EndIf
      FlipBuffers()
Until Quit=1
End



Procedure.f curveangle(newangle.f,oldangle.f,increments.f)
      If increments > 1
            If (oldangle + 360) - newangle < newangle - oldangle
                  oldangle = 360 + oldangle 
            EndIf
            If (newangle + 360) - oldangle < oldangle - newangle
                  newangle = 360 + newangle
            EndIf
            oldangle = oldangle - (oldangle - newangle) / increments
      EndIf
      
      If increments <= 1
            ProcedureReturn newangle
      EndIf

      ProcedureReturn oldangle
EndProcedure


Procedure.f ReturnDegAngle(x1.f,y1.f,x2.f,y2.f) ; DEGREE
      Protected A.f, b.f, c.f, Angle.f
      A.f = x1-x2
      b.f = y1-y2
      c.f = -Sqr(A*A+b*b)
      Angle.f = ACos(A / c) * 180 / #PI
      If y1 < y2 : Angle = 360 - Angle : EndIf
      ProcedureReturn Abs(Angle - 360)
EndProcedure


Procedure track_SmoothPoint(*A.ENTITY,*B.ENTITY, turnspeed.f=1.0)
      Protected AngDif.f, temp_yaw.f

      AngDif = ReturnDegAngle(*A\x,*A\y,*B\x,*B\y)
      temp_yaw.f = curveangle(AngDif, *A\Angle, turnspeed)
         *A\Angle = temp_yaw
EndProcedure

Procedure.f DistanceEntre2Points(ax.f, ay.f, bx.f, by.f)
ProcedureReturn Sqr(Pow((bx - ax), 2) + Pow((by - ay), 2))
EndProcedure
Mais bon, pas la peine de se casser plus la tête, c'est un petit jeu que je fais à temps perdu et je ne sais même pas si je le finirai un jour.

C'est seulement pour me frotter un poil à la lib Screen2D.

Graph100, l'important c'est de participer :D.

Bye et merci.
comtois
Messages : 5186
Inscription : mer. 21/janv./2004 17:48
Contact :

Re: if..else..endif et trigonométrie code de Cpl.Bator

Message par comtois »

graph100 a écrit :bien vu ;) mais c'est dommage :s
Juste pour info, pour un float il faut utiliser Mod()

Code : Tout sélectionner

Mod(Angle, 360)
http://purebasic.developpez.com/
Je ne réponds à aucune question technique en PV, utilisez le forum, il est fait pour ça, et la réponse peut profiter à tous.
Geo Trouvpatou
Messages : 471
Inscription : dim. 23/déc./2007 18:10

Re: if..else..endif et trigonométrie code de Cpl.Bator

Message par Geo Trouvpatou »

Salut.
comtois a écrit :Juste pour info, pour un float il faut utiliser Mod()

Code : Tout sélectionner

Mod(Angle, 360)
Fallait le savoir parce que dans la doc il n'y a rien.

Par contre génial.
Sur mon circuit test en 8 (Ci-dessus) j'ai boosté le #turnspeed à 12 pour mieux voir l'effet d'arrondi des virages.
Avec :

Code : Tout sélectionner

If Voiture\Angle => 360
      Voiture\Angle = 0
EndIf

If Voiture\Angle < 0
      Voiture\Angle = 359
EndIf 
Le virage du checkpoint 4 est violent, alors qu'avec :

Code : Tout sélectionner

Mod(Voiture\Angle, 360)
le virage est plus doux.
Mais cela n'empêche que les virages à droite sont plus jolis.

Merci Comtois.
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: if..else..endif et trigonométrie code de Cpl.Bator

Message par G-Rom »

comtois a écrit :
graph100 a écrit :bien vu ;) mais c'est dommage :s
Juste pour info, pour un float il faut utiliser Mod()

Code : Tout sélectionner

Mod(Angle, 360)

Merci Comtois , je connaissais pas cette commande ;)
Répondre