Page 1 sur 3

[RESOLU] (& meme + :))un sprite qui se déplace vers un autre

Publié : mar. 08/mars/2011 23:33
par blendman
salut

Je cherche la technique pour faire qu'un sprite se déplace en ligne vers un autre.

Un exemple :
- un magicien lance une boule de feu vers un ennemi.

Je ne sais pas trop comment faire ça. J'ai réussi si ce n'est pas une ligne droite.

Merci

Re: un sprite qui se déplace vers un autre

Publié : mer. 09/mars/2011 0:14
par G-Rom

Code : Tout sélectionner

; Cpl.Bator
; PureBasic 4.10
CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  Structure point
    x.f
    y.f
  EndStructure
CompilerEndIf

#SW=800
#SH=600

InitSprite() : InitKeyboard() : InitMouse()
OpenScreen(#SW,#SH,32,"")



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

Structure ENTITY
  Position.VECTOR2
  Angle.f
EndStructure


;-Declarations des fonctions
Declare DrawArrow(Lenght.l , x.f , y.f , Angle.f)
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)



; ************************************************************************************
#NB_ARROW = 3
Dim Arrow.ENTITY(#NB_ARROW)

For i = 1 To #NB_ARROW
  Arrow(i)\Position\x = Random(#SW)
  Arrow(i)\Position\y = Random(#SH)
  Arrow(i)\Angle      = 0
Next
; ************************************************************************************


; Cible des "arrow" , coordonées de la souris pour la position
Target.ENTITY



CompilerIf #PB_Compiler_OS = #PB_OS_Linux
  KeyboardMode(#PB_Keyboard_International)
CompilerEndIf


Repeat
  
ExamineMouse()
ExamineKeyboard()
ClearScreen(0)

Target\Position\x = MouseX()
Target\Position\y = MouseY()

            StartDrawing(ScreenOutput())
                Circle(Target\Position\x,Target\Position\y,2,255)
            StopDrawing()


                For i = 1 To #NB_ARROW
                    DrawArrow(50 , Arrow(i)\Position\x , Arrow(i)\Position\y , Arrow(i)\Angle)
                    track_SmoothPoint(Arrow(i),Target,20)
                   
                    Arrow(i)\Position\x + 1 *Cos(Arrow(i)\Angle*#PI/180)
                    Arrow(i)\Position\y + 1 *Sin(Arrow(i)\Angle*#PI/180)
                Next



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
  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)
    AngDif = ReturnDegAngle(*A\position\x,*A\position\y,*B\position\x,*B\position\y)
    temp_yaw.f = curveangle(AngDif,*A\Angle,turnspeed)
    *A\Angle = temp_yaw
EndProcedure



Procedure DrawArrow(Lenght.l , x.f , y.f , Angle.f)

          Protected ArrowA.Point,ArrowB.Point
          Protected ArrowBranchA.Point,ArrowBranchB.Point
         
         
         
          ArrowA\x = x + (Lenght/2) * Cos(Angle*#PI/180)
          ArrowA\y = y + (Lenght/2) * Sin(Angle*#PI/180)
         
          ArrowB\x = x - (Lenght/2) * Cos(Angle*#PI/180)
          ArrowB\y = y - (Lenght/2) * Sin(Angle*#PI/180)
         
         
          ArrowBranchA\x = ArrowA\x - (Lenght/3) * Cos((Angle+45)*#PI/180)
          ArrowBranchA\y = ArrowA\y - (Lenght/3) * Sin((Angle+45)*#PI/180)
         
          ArrowBranchB\x = ArrowA\x - (Lenght/3) * Cos((Angle-45)*#PI/180)
          ArrowBranchB\y = ArrowA\y - (Lenght/3) * Sin((Angle-45)*#PI/180)
         
         
            StartDrawing(ScreenOutput())
                LineXY(ArrowA\x,ArrowA\y,ArrowB\x,ArrowB\y,255)
                LineXY(ArrowA\x,ArrowA\y,ArrowBranchA\x,ArrowBranchA\y,255)
                LineXY(ArrowA\x,ArrowA\y,ArrowBranchB\x,ArrowBranchB\y,255)
                Circle(x+1,y+1,2,255)
            StopDrawing()
EndProcedure

Re: un sprite qui se déplace vers un autre

Publié : mer. 09/mars/2011 7:23
par jbernard13
G-rom donne Moi des cours pour crée un jeux ... tu es trop fort .

Re: un sprite qui se déplace vers un autre

Publié : mer. 09/mars/2011 8:39
par blendman
G-rom : merci pour ce code, il est très intéressant ;).
Maintenant, je vais le simplifier pour que lorsque l'objet arrive sur la cible, il disparaisse, et aussi pour qu'il se déplace uniquement en ligne droite :)

Re: un sprite qui se déplace vers un autre

Publié : mer. 09/mars/2011 12:26
par djes
Sinon le principe est celui de l'équation de droite, pour laquelle il existe trente six algos.
Le plus simple à mon avis (donc mon préféré, celui dont je me sers pour les tests, et avant optim) : si tu as une variable u.f qui va de 0 à 1, et deux points A et B, tu obtiens ta trajectoire comme ça...

Code : Tout sélectionner

x = u * (xB - xA)
y = u * (yB - yA)
Enfantin, non ? :mrgreen:

Re: un sprite qui se déplace vers un autre

Publié : mer. 09/mars/2011 12:41
par blendman
djes a écrit :Sinon le principe est celui de l'équation de droite, pour laquelle il existe trente six algos.
Le plus simple à mon avis (donc mon préféré, celui dont je me sers pour les tests, et avant optim) : si tu as une variable u.f qui va de 0 à 1, et deux points A et B, tu obtiens ta trajectoire comme ça...

Code : Tout sélectionner

x = u * (xB - xA)
y = u * (yB - yA)
Enfantin, non ? :mrgreen:
c'est quoi cette variable u ? la vitesse ?

Que dois-je faire si je veux que le sprite aille de A à B en ligne droite ? (en s'arrêtant à B) :D

EDIT : bon, j'ai testé ce code, normalement, ça devrait marcher :
(block() est une liste)
\vitese = 0 à la création de l'élément de la liste.

Code : Tout sélectionner

With block()      
      If \vitesse <=1
        \position\x  + \vitesse * (\cible\x - \position\x)
        \position\y  + \vitesse * (\cible\y - \position\y)
        \vitesse +0.1
      EndIf
endif     

Re: un sprite qui se déplace vers un autre

Publié : mer. 09/mars/2011 13:52
par djes
La vitesse, non, c'est plutôt la position entre A et B. À 0, tu es sur A, à 1, tu es sur B, à 0.5, tu es au milieu. Dans ton exemple, la vitesse est conditionnée par le 0.1, et elle varie suivant la distance entre A et B ; c'est pour ça que tu ne peux simplement utiliser cette formule si tu veux que la vitesse soit constante quels que soient les points de départ et d'arrivée.

Re: un sprite qui se déplace vers un autre

Publié : mer. 09/mars/2011 14:01
par G-Rom
il te manque quelques notions sur les vecteurs.
voici un petit code commenté de quoi t'éclairer sur le sujet , c'est la base.

@+

Code : Tout sélectionner

Structure Vector2
  x.f
  y.f
EndStructure


A.Vector2
B.Vector2


; Départ
A\x = 100
A\y = 100

;Arrivé
B\x = 650
B\y = 1450

;Direction
Direction.Vector2
; La direction se calcul entre soustrayant l'arrivé du départ
Direction\x = B\x - A\x
Direction\y = B\y - A\y

; Calcul de la longueur du vecteur Direction
Longueur.f = Sqr( Direction\x * Direction\x    +    Direction\y * Direction\y )
; Normalise le vecteur Direction ( Vecteur entre 0 & 1 )
If Longueur > 0
  Direction\x = Direction\x / Longueur
  Direction\y = Direction\y / Longueur
EndIf 

; Calcul de la nouvelle position :

vitesse.f = 3.5 ; Amuse toi à changer la valeur

NouvellePosition.Vector2
NouvellePosition\x = A\x + (Direction\x * vitesse)
NouvellePosition\y = A\y + (Direction\y * vitesse)

Debug "Depart en 100x100"
Debug ""
Debug "Vitesse = "+StrF(vitesse)
Debug ""
Debug "Nouveau X = " +StrF(NouvellePosition\x)
Debug "Nouveau Y = " +StrF(NouvellePosition\y)


Re: un sprite qui se déplace vers un autre

Publié : mer. 09/mars/2011 15:04
par blendman
G-Rom a écrit :il te manque quelques notions sur les vecteurs. voici un petit code commenté de quoi t'éclairer sur le sujet , c'est la base.
salut G-rom

Effectivement, il me manque beaucoup de notions sur les vecteurs (disons que je les ai oublié).
Merci pour ton exemple, je vais le regarder et l'étudier de prêt, histoire de voir comment cela fonctionne ;).

djes a écrit :La vitesse, non, c'est plutôt la position entre A et B. À 0, tu es sur A, à 1, tu es sur B, à 0.5, tu es au milieu. Dans ton exemple, la vitesse est conditionnée par le 0.1, et elle varie suivant la distance entre A et B ; c'est pour ça que tu ne peux simplement utiliser cette formule si tu veux que la vitesse soit constante quels que soient les points de départ et d'arrivée.
j'ai enlevé la vitesse qui augmente et j'ai changé un paramètre (le previous\x et \y) et maintenant la vitesse est constante :).

Finalement, je suis moins une quiche que je ne le pensais lol.

Le code (ce qui a changé):

Code : Tout sélectionner

If ListSize(block()) <> 0 
    For i =0 To ListSize(block())-1
    If SelectElement(block(), i)   
        block()\position\x  + (block()\vitesse * (block()\cible\x - block()\previous\x))/100
        block()\position\y  + (block()\vitesse * (block()\cible\y - block()\previous\y))/100
      EndIf
    EndIf
    ChangeCurrentElement(block(),i)
et l'exemple complet :

Code : Tout sélectionner

;{******************** infos ******************
; code release mouse : netmaestro
;  le reste : ben, moi :)
; pb : 4.51
; déplacement de personnage (un clic and go de base) et lançage de sorts à la volée :)
;}


;{ ************************enumeration ***********************
Enumeration
#window
#player 
#block
EndEnumeration
#ScreenW = 800
#ScreenH = 600
;}

;{ ************************ variables ************************
Global vitesse= 3
Global inscreen = 1
Global mouseClic = 0
ShowCursor_(1)
;}

;{ ************************ Structures ************************

Structure s_block
  name.s
  position.Point
  previous.Point
  vitesse.f 
  cible.Point
  cible_ok.i
  sprite.i
EndStructure

Global NewList block.s_block()

Global Dim player.s_block(0)

player(0)\name = "player"
player(0)\position\x = 15
player(0)\position\y = 15
player(0)\previous\x = 15 
player(0)\previous\y = 15 
player(0)\vitesse = 3
player(0)\cible\x=15
player(0)\cible\y=15
player(0)\sprite = #player
player(0)\cible_ok=0
;}

;{ ************************ declare ***************************
Declare gestion_souris()
Declare evenementClavier()
Declare Player_move()
Declare affichage()
Declare instance_create()
Declare Sort_move()
;}

;{ ************************ inititialisation *****************
InitKeyboard () 
InitSprite()
InitSprite3D()
InitMouse()
UsePNGImageDecoder()
;}

;{ ************************ open window *********************

OpenWindow(#window, 0, 0,#ScreenW, #ScreenH, "Collision" , #PB_Window_SystemMenu|#PB_Window_BorderLess |#PB_Window_ScreenCentered )
OpenWindowedScreen( WindowID (#window),0,0, 800,600, 1, 0,0)

;}

;{ ************************ sprite et loading ***************

LoadSprite(#player,"col.png")
LoadSprite(#block,"blockCollision.png")

TransparentSpriteColor(#player,RGB(255,0,0))
TransparentSpriteColor(#block,RGB(255,0,0))
;}

;{ ************************ boucle principale ***************

Repeat

Event= WindowEvent ()

ExamineKeyboard ()
ExamineMouse()
gestion_souris()

affichage()
evenementClavier()
Player_move()

instance_create()
Sort_move()

; With block()
;       If SpritePixelCollision(#player,player(0)\position\x,player(0)\position\y,#block,\position\x,\position\y)
;             player(0)\vitesse =0
;             player(0)\position\x = \previous\x 
;             player(0)\position\y = \previous\y   
;           Else
;             player(0)\vitesse = 3
;       EndIf
; EndWith



FlipBuffers ()
ClearScreen (RGB (125,125,125)) 

Until Event= #PB_Event_CloseWindow Or KeyboardPushed ( #PB_Key_Escape ) 
;}

Procedure evenementClavier()
  If KeyboardPushed ( #PB_Key_Up )
     ForEach block()
         With block() 
           If \name = "player"
             \previous\y = \position\y
             \position\y - \vitesse
           EndIf
        EndWith 
      Next
  EndIf


If KeyboardPushed ( #PB_Key_Down )
     ForEach block()
         With block() 
           If \name = "player"
             \previous\y = \position\y
              \position\y + \vitesse
           EndIf
        EndWith 
      Next
EndIf


 If KeyboardPushed ( #PB_Key_Left )
     ForEach block()
   With block() 
     If \name = "player"
       \previous\x = \position\x
        \position\x - \vitesse
         EndIf
  EndWith 
Next
EndIf

If KeyboardPushed ( #PB_Key_Right )
    ForEach block()
      With block() 
           If \name = "player"
              \previous\x = \position\x
              \position\x +\vitesse       
          EndIf
      EndWith  
    Next
EndIf
EndProcedure

Procedure Player_move()
  If MouseButton(#PB_MouseButton_Left) =1 
        player(0)\cible_ok = 1
        player(0)\cible\x = MouseX()
        player(0)\cible\y = MouseY()
  EndIf

  With player(0)
    If \cible_ok = 1 And \name = "player"
      If \position\x < \cible\x
        \position\x + \vitesse
       ElseIf \position\x > \cible\x
         \position\x - \vitesse
      EndIf
      If \position\y < \cible\y
        \position\y + \vitesse/2
       ElseIf \position\y > \cible\y
         \position\y - \vitesse/2
       EndIf
     EndIf
   EndWith
EndProcedure

Procedure instance_create()  
  If MouseButton(#PB_MouseButton_Right) =1 And  mouseClic = 0
    mouseClic = 1
    vitesseSort = 0
    ;ClearList(block())
    AddElement(block())
      With block()
        \name = "block"
        \cible\x = MouseX()
        \cible\y = MouseY()
        \position\x = player(0)\position\x
        \position\y = player(0)\position\y
        \previous\x = player(0)\position\x
        \previous\y = player(0)\position\y
        \sprite = #block
        \vitesse = 2
      EndWith 
      nbre_element = ListSize(block())
     
ElseIf MouseButton(#PB_MouseButton_Right) =0
  mouseClic = 0
EndIf 
EndProcedure

Procedure gestion_souris() 
  mx = WindowMouseX(#window):my = WindowMouseY(#window)
  If inscreen = 1
        If mx> #ScreenW-2 Or my> #ScreenH-2 Or mx<1 Or my<1
          inscreen = 0
          ReleaseMouse(1)             
        EndIf     
  ElseIf mx <#ScreenW-1 And my < #ScreenH-1 And mx > 0 And my > 0 
      ReleaseMouse(0)
      MouseLocate(mx,my)
      inscreen = 1
  EndIf
EndProcedure

Procedure Sort_move()
   
  If ListSize(block()) <> 0 
    For i =0 To ListSize(block())-1
    If SelectElement(block(), i)    
        block()\position\x  + (block()\vitesse * (block()\cible\x - block()\previous\x))/100
        block()\position\y  + (block()\vitesse * (block()\cible\y - block()\previous\y))/100
    EndIf
    ChangeCurrentElement(block(),i)
    Next
 EndIf 
  EndProcedure


Procedure affichage()
  DisplayTransparentSprite(player(0)\sprite, player(0)\position\x, player(0)\position\y) 
  ForEach block()
    DisplayTransparentSprite(block()\sprite, block()\position\x, block()\position\y)  
  Next
EndProcedure

Re: un sprite qui se déplace vers un autre

Publié : mer. 09/mars/2011 16:07
par Cool Dji
Manque juste un lien sur les fichiers de sprite et ça pourra compiler... :lol:

Re: un sprite qui se déplace vers un autre

Publié : mer. 09/mars/2011 16:17
par blendman
Cool Dji a écrit :Manque juste un lien sur les fichiers de sprite et ça pourra compiler... :lol:
les 2 sprites, c'est juste 2 bêtes losanges (n'importe quel sprite irait en fait :))
mais les voici :
Image
Image

Re: un sprite qui se déplace vers un autre

Publié : mer. 09/mars/2011 16:26
par Cool Dji
Ben kektafoutu ?
ça se déplace pas en ligne droite !!
C'est plus compliqué en ligne droite :mrgreen:

Faut reprendre le code de G-Rom.

A moins que tu souhaites garder ce type de déplacement, mais les déplacements vont pas être réalistes, surtout quand tu vas introduire des obstacles à éviter...

Re: un sprite qui se déplace vers un autre

Publié : mer. 09/mars/2011 16:43
par blendman
Cool Dji a écrit :Ben kektafoutu ?
ça se déplace pas en ligne droite !!
C'est plus compliqué en ligne droite :mrgreen:

Faut reprendre le code de G-Rom.

A moins que tu souhaites garder ce type de déplacement, mais les déplacements vont pas être réalistes, surtout quand tu vas introduire des obstacles à éviter...
heu, c'est le sort qu'il faut regarder (clic droit, le losange rouge) pas le le losange bleu :D

Re: un sprite qui se déplace vers un autre

Publié : mer. 09/mars/2011 16:49
par Cool Dji
Wouai, bon ça va :mrgreen: :mrgreen:

En revanche, ya un truc à améliorer : la vitesse de déplacement du sort est proportionnelle à l'éloignement de la cible par rapport au lancer => c'est pas bon, ça !!

Re: un sprite qui se déplace vers un autre

Publié : mer. 09/mars/2011 16:55
par blendman
Cool Dji a écrit :Wouai, bon ça va :mrgreen: :mrgreen:

En revanche, ya un truc à améliorer : la vitesse de déplacement du sort est proportionnelle à l'éloignement de la cible par rapport au lancer => c'est pas bon, ça !!
oui, je sais c'est ce que j'essaie de corriger :) (en faisant en sorte que ce soit le plus simple possible) :)

Si tu as une idée, je suis preneur ;).

EDIT : je suis en train d'essayer d'intégrer l'exemple de G-rom pour voir si j'ai bien tout compris :D