Page 1 sur 1

[ok]Sprite : rotate un sprite autour d'un autre+ sa rotation

Publié : sam. 19/mars/2016 9:35
par blendman
Salut

Voilà, j'aimerai concevoir un système de bones pour créer des animations de sprites.

Pour ça, j'ai besoin
- d'avoir un sprite qui peut faire une rotation en fonction de la rotation d'un autre sprite (dans mon exemple, il tourne autour du sprite)
- que ce sprite puisse tourner sur lui-même en plus.

En gros, comme une lune qui tournerait autour d'une planète qui tourne sur elle-même.

J'ai donc repris le code fourni par Stargate qui permet de faire une rotation en un centre précis.
J'arrive donc à faire tourner le sprite rouge autour du sprite normal, mais je n'arrive pas à faire tourner en même temps le sprite rouge sur lui-même.

Auriez-vous une idée pour réaliser ça ?

Code : Tout sélectionner

#Window_main = 0

If InitSprite() =0 Or InitKeyboard()  =0
    End
EndIf

Procedure SpriteTransformation(Sprite.i, X.f, Y.f, Width.f, Height.f, Angle.f)
   Protected Cos.f = Cos(Radian(Angle))
   Protected Sin.f = Sin(Radian(Angle))
   TransformSprite(Sprite, X*Cos-Y*Sin, X*Sin+Y*Cos, (X+Width)*Cos-Y*Sin, (X+Width)*Sin+Y*Cos, (X+Width)*Cos-(Y+Height)*Sin, (X+Width)*Sin+(Y+Height)*Cos, X*Cos-(Y+Height)*Sin, X*Sin+(Y+Height)*Cos)
EndProcedure


flag = #PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_ScreenCentered|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget
WinW =800
WinH =600
If OpenWindow(#Window_main,0,0,WinW,WinH, "Sprite", Flag) = 0
    End
EndIf 
If OpenWindowedScreen(WindowID(0), 0,0,WinW,WinH) = 0
    End
EndIf
LoadSprite(0,#PB_Compiler_Home+"Examples\Sources\Data\PurebasicLogo.bmp")
CopySprite(0,1)
W =SpriteWidth(0)
H =SpriteHeight(0)
r.d = 0.2
ZoomSprite(1,w*r,h*r)
ZoomSprite(0,w*r,h*r)
x = 100
dir = 1
y = 300

Repeat
    
    Repeat
        
        EventID     = WindowEvent()
        
        Select EventID
                
            Case #PB_Event_CloseWindow 
                End
                
        EndSelect
        
    Until event = 0
    
    ClearScreen(RGB(100,100,100))
    
    x+dir
    If x > 500
        dir = -dir
    ElseIf x <50
        dir = -dir
    EndIf
    
    a+1
    If a > 360
        a = 0
    EndIf
    b +1
    If b> 360
        b = 0
    EndIf
    
    RotateSprite(1,b,0) ; c'est annuler par la procédure en dessous
    SpriteTransformation(1, -100,-100, w*r, h*r ,b)
    ; 
    DisplayTransparentSprite(1,50+x,y,255,#Red)
        
    
    RotateSprite(0,a,0)
    DisplaySprite(0,x,y)
    FlipBuffers()
    
Until Quit = 1
En gros, voici ce que je cherche à obtenir en finalité :
Image

Si vous avez des pistes ou une idées, ça m'intéresse grandement :D

Re: Sprite : rotate un sprite autour d'un autre+ sa rotation

Publié : sam. 19/mars/2016 11:26
par Micoute

Code : Tout sélectionner

;***************variables utilisées**********************
xs.f=260;   pour le soleil
ys.f=210

xt.f=0;   pour la terre
yt.f=0

xl.f=0;   pour la lune
yl.f=0

rt.f=160; rayon de l'orbite terrestre
rl.f=50; rayon de l'orbite lunaire

theta.f=0; angle pour la rotation de la terre
phi.f=0; angle pour la rotation de la lune
psi.f=0; angle de rotation de la lune par rapport au soleil
pi.f=3.1415927
;*************initialisation**********************
InitSprite()
InitKeyboard()

OpenWindow (1, 1,1, 600, 500 , "Phases lunaires" , #PB_Window_SystemMenu) ; on ouvre une fenetre
OpenWindowedScreen ( WindowID (1) , 0, 0, 600, 500, 1, 1, 1) ; on met un ecran dedans !!


;***********************sprite terre***************************************

CreateSprite (1,32,32) ;terre éclairée sprite 32*32
StartDrawing ( SpriteOutput (1))
Circle (16,16, 16, $DEDA1F)
StopDrawing ()

CreateSprite (2,32,32) ; terre non éclairée sprite 32*32
StartDrawing ( SpriteOutput (2))
Circle (16,16, 16, $B21017)
StopDrawing ()

ClipSprite(1,0,0,16,32);découpage terre éclairée
ClipSprite(2,16,0,16,32); découpage terre non éclairée

DisplaySprite(1,100,100);affichage des deux sprites
DisplaySprite(2,116,100)

GrabSprite(1,100,100,32,32) ;capture d'écran et création du sprite(3) terre
                                        ; moitié éclairée moitié sombre



;******************************sprite lune**************************************

CreateSprite (4,16,16) ;lune éclairée sprite 16*16
StartDrawing ( SpriteOutput (4))
Circle (8,8,8, $EBEBEB)
StopDrawing ()

CreateSprite (5,16,16) ; lune non éclairée sprite 16*16
StartDrawing ( SpriteOutput (5))
Circle (8,8, 8, $737271)
StopDrawing ()

ClipSprite(4,0,0,8,16);découpage lune éclairée
ClipSprite(5,8,0,8,16); découpage lune non éclairée

DisplaySprite(4,100,132);affichage des deux sprites
DisplaySprite(5,108,132)

GrabSprite(2,100,132,16,16,#PB_Sprite_AlphaBlending) ;capture d'écran et création du sprite(6) lune


;*********************************** sprite soleil******************************
CreateSprite (7,64,64)
StartDrawing ( SpriteOutput (7))
Circle(32,32,32,RGB(249, 244, 89))
StopDrawing ()

;***************************programme principal****************************************


Repeat ; boucle principale
   
   Event= WindowEvent () ; on regarde si quelqu'un a cliqué sur la croix pour quitter
   
   If Event= #PB_Event_CloseWindow
      End
   EndIf
   
   While WindowEvent () : Wend
   
   If ExamineKeyboard()
      If KeyboardPushed(#PB_Key_Escape)
         End
      EndIf
      If KeyboardReleased(#PB_Key_F1)
         Pause=1-Pause 
      EndIf
      If KeyboardReleased(#PB_Key_F2)
         Pause=1
         i=Val(InputRequester("Titre","Donnez l'angle en degré ",Str(i)))
      EndIf
   EndIf
   
   ; ***********calcul des trajectoires*************
   
   If Pause=0 
      i + 1
      If i>=360 
        i=0
      EndIf  
   EndIf
   
   theta=pi*i/180 ;conversions en radians
   phi=pi*i/15
   
   xt=xs+rt*Cos(-theta)+16; coords de la terre
   yt=ys+rt*Sin(-theta)+16
   xl=xt+rl*Cos(-phi)+8; coords de la lune
   yl=yt+rl*Sin(-phi)+8
   
   If (xl-xs)>0    ;phénomènes mystiques avec l'arctangente!
      psi=180*ATan((yl-ys)/(xl-xs))/pi
   EndIf
   
   If (xl-xs)<0
      psi=180*(ATan((yl-ys)/(xl-xs))/pi-1); surtout ici! faut que je révise ma trigo!
   EndIf
   
   
   ;****************affichage des sprites***************************
   ClearScreen (0) ; <--- ceci efface l'ecran !!
   
   DisplaySprite(7,xs,ys)         ; affichage soleil
   
      RotateSprite(1,-theta*180/pi,0); rotation de la terre avec l'angle en degrés
      RotateSprite(2,psi,0)       ; rotation de la Lune
      DisplaySprite(1,xt,yt)      ; affichage terre
      DisplaySprite(2,xl,yl)      ; affichage lune
   
   ;Affiche les angles
   StartDrawing(ScreenOutput())
      FrontColor(RGB(255,255,255))
      DrawingMode(1)
   ;   DrawText(xt,yt-16, StrF(Theta,2))
   ;   DrawText(xl,yl-16, StrF(phi,2))
   StopDrawing()
   
   FlipBuffers () ; 
   
   Delay(50)
    
ForEver

Re: Sprite : rotate un sprite autour d'un autre+ sa rotation

Publié : sam. 19/mars/2016 11:30
par blendman
Dobro : merci pour tes exemples, ton exemple avec le bras c'est exactement ce que je recherche ! :D
Tu saurais l'adapter avec les sprites ? (et la procédure de stargate pour changer le centre de rotation). Car j'ai essayé mais je n'arrive pas à adapter ça (pour le moment ^^).
En tout cas bravo et encore merci pour cet exemple !

Micoute : merci, je vais regarder ton code ;).

Re: Sprite : rotate un sprite autour d'un autre+ sa rotation

Publié : sam. 19/mars/2016 11:58
par blendman
Dobro : encore un immense merci ! Vraiment merci. Tu as encore cartonné !
Grâce à tes explications, j'ai réussi, bravo à toi ;).

J'ai modifié légèrement ton code pour avoir les sprites :

Code : Tout sélectionner

;***********************************************
;Titre  :*bras_avant_bras
;Auteur  : Dobro
;Date  :19/03/2016
;Heure  :11:11:56
;Version Purebasic :  PureBasic 5.42 LTS (Windows - x86)
;Version de l'editeur :EPB V2.62
; Libairies necessaire : Aucune
;***********************************************

#dobro =1
#Police =1
#Sprite =1
;
Declare.s avantbras(taille,posx,posy,angle_triangle,couleur)
Declare.s  bras(taille,posx,posy,angle_triangle,couleur)

Procedure SpriteTransformation(Sprite.i, X.f, Y.f, Width.f, Height.f, Angle.f)
   Protected Cos.f = Cos(Radian(Angle))
   Protected Sin.f = Sin(Radian(Angle))
   TransformSprite(Sprite, X*Cos-Y*Sin, X*Sin+Y*Cos, (X+Width)*Cos-Y*Sin, (X+Width)*Sin+Y*Cos, (X+Width)*Cos-(Y+Height)*Sin, (X+Width)*Sin+(Y+Height)*Cos, X*Cos-(Y+Height)*Sin, X*Sin+(Y+Height)*Cos)
EndProcedure

; ***********************************
Resultat = InitSprite ()
FontID = LoadFont ( #Police , "arial" , 18, #PB_Font_Bold )
ExamineDesktops()
Global EcranX = DesktopWidth(0): ;=largeur de l'ecran
Global EcranY = DesktopHeight(0):;=hauteur de l'ecran
WindowID = OpenWindow (1, 0, 0, EcranX, EcranY, "hello" ,#PB_Window_SystemMenu|#PB_Window_BorderLess |#PB_Window_ScreenCentered )
WindowID = WindowID (1)
Result = OpenWindowedScreen ( WindowID ,0,0, EcranX, EcranY, 1, 0,0)
Resultat = InitKeyboard ()
largeur=100
Resultat = InitMouse ()

CreateSprite(0,100,20)
CreateSprite(1,100,20)

If StartDrawing(SpriteOutput(1))
    Box(0,0,100,20,#Red)
    StopDrawing()
EndIf


Repeat
     ; ****************************************
    ;;;; DisplaySprite ( #Sprite , 0, 0)
    event= WindowEvent ()
    
    
    ExamineKeyboard ()
    xa=EcranX/2:ya=EcranY/2 ; xa et ya = centre de l'ecran
      ClearScreen(RGB(120,120,120))
    ;taille= taille du  bras
    ; posx et posy = position du bras dans l'ecran
    ; angle_bras= orientation du bras en degres
    ; couleur =couleur du contour du bras
     
  
    
    
    ; RotateSprite(0,angle_du_avantbras,0)
    SpriteTransformation(0,0,-10,100,20,angle_du_avantbras)
    DisplaySprite(0,xa,ya)
    
    ;RotateSprite(1,2,1)
    SpriteTransformation(1,0,-10,100,20,angle_rotation_du_bras)
    DisplaySprite(1,posx,posy)
    
    
    
    ; ***********************************************
    ; juste une rotation de l'avant bras (violet )
    taille_avant_bras=100 ; longueur de l'avant bras   
    couleur=RGB (255,0,255) ; couleur de l'avant bras
    angle_du_avantbras=angle_du_avantbras+1 ; angle de l'avant bras (ici ça tourne en rond )
    xa=taille* Cos (angle_du_avantbras*2* #PI /360)+EcranX/2 ; Formule du cercle !
    ya=taille* Sin (angle_du_avantbras*2* #PI /360)+EcranY/2 ; Formule du cercle !
    
    
    ;ceci determine la rotation du bras lui meme
    c$=avantBras(taille_avant_bras,xa,ya,angle_du_avantbras,couleur) ; c$ recupere le noeuf d'attache
    
    ; juste une rotation du bras
    taille_bras=100 ; longueur du bras
    couleur=RGB (0,255,0) ; couleur du bras (Vert )
    angle_rotation_du_bras=angle_rotation_du_bras+3 ; rotation du bras (ici il tourne en rond ) mais on peut preciser un angle en degres ;o)
    If angle_rotation_du_bras<0
        angle_rotation_du_bras=359
    EndIf
    posx=Val(StringField(c$,1," "))
    posy=Val(StringField(c$,2," "))
    
    
    c$ = Bras(taille_bras,posx,posy,angle_rotation_du_bras,couleur) ; la formule de rotation (du cercle ) est iuntégré dans la procedure Bras ;o)
    pos1x=Val(StringField(c$,1," "))
    pos1y=Val(StringField(c$,2," "))
    
    
   
   
    
    
    
    
    
    
    FlipBuffers (): ; affiche l'ecran

    
    If KeyboardPushed ( #PB_Key_Escape ) ; press Esc to quit
        End
    EndIf
Until event= #PB_Event_CloseWindow

Procedure.s avantBras(taille,posx,posy,angle_triangle,couleur)
    StartDrawing ( ScreenOutput (  ))
    DrawText (1,1, Str (angle_triangle))
    xf=taille* Cos (angle_triangle*2* #PI /360)+posx
    yf=taille* Sin (angle_triangle*2* #PI /360)+posy
    LineXY (posx, posy, xf, yf ,couleur)
    StopDrawing ()
    ProcedureReturn Str(xf)+" "+Str(yf) ; ruse de guerre pour ressortir 2 parametres d'une procedure
EndProcedure

Procedure.s Bras(taille,posx,posy,angle_triangle,couleur)
    StartDrawing ( ScreenOutput (  ))
    DrawText (1,1, Str (angle_triangle))
    xf=taille* Cos (angle_triangle*2* #PI /360)+posx
    yf=taille* Sin (angle_triangle*2* #PI /360)+posy
    LineXY (posx, posy, xf, yf ,couleur)
    StopDrawing ()
    ProcedureReturn Str(xf)+" "+Str(yf) ; ruse de guerre pour ressortir 2 parametres d'une procedure
EndProcedure

;
; Epb

Re: Sprite : rotate un sprite autour d'un autre+ sa rotation

Publié : sam. 19/mars/2016 12:38
par Micoute
Je demande qu'on m'excuse, car j'ignorais que le code source était de Huitbit et je le remercie pour l'occasion.

Re: Sprite : rotate un sprite autour d'un autre+ sa rotation

Publié : sam. 19/mars/2016 13:20
par falsam
Hey Blendman :D

Un code de chez rosetta qui devrait te plaire https://rosettacode.org/wiki/Animate_a_ ... #PureBasic

Re: Sprite : rotate un sprite autour d'un autre+ sa rotation

Publié : sam. 19/mars/2016 14:42
par blendman
Falsam : yep, ça me plait :) Je dois ajouter l'interpolation autre que lineaire dans mon soft ^^.