[ok] SpriteRotation et boite englobante

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

[ok] SpriteRotation et boite englobante

Message par blendman »

salut

J'essaie de trouver les coordonnées des points x1/y1,x2/y2,x3/y3,x4/y4 d'un sprite après une rotation, ces points étant les sommets créés par la boite englobant ce sprite.
x1/y1 = haut-gauche
x2y2 = haut droit
x3y3 = bas droit
x4y4 = bas gauche

Voici une image pour illustrer ce que je cherche à obtenir (la légende est en anglais, mais on compris l'idée ^^):
Image

En fait, j'aimerai ensuite pouvoir utiliser ces points (x1y1,x2y2...) pour changer la taille ou la rotation de mon sprite dans mes éditeurs de niveau ou d'animation.

Donc, si vous avez une idée pour récupérer ces coordonnées après une rotation (et un changement de taille éventuellement) ça m'intéresse :).
Merci.
Dernière modification par blendman le mer. 16/mars/2016 10:43, modifié 1 fois.
Marc56
Messages : 2198
Inscription : sam. 08/févr./2014 15:19

Re: SpriteRotation et boite englobante

Message par Marc56 »

C'est plus ou moins comme pour calculer les coordonnées du bout de l'aiguille d'une pendule: Sin() et Cos()
Il y a toujours un triangle rectangle quelque part.
https://fr.wikipedia.org/wiki/Fonction_ ... _rectangle

Ne pas oublier (comme je l'avais fais :roll: ) que les calculatrices travaillent par défaut en Degrés, mais les langages de programmation en Radian.
Je n'avais réussi pour tracer ma pendule (en mode réinventer le roue pour comprendre) qu'à partir du moment ou j'ai tracé sur papier plusieurs positions types :o

et l'aide mémoire de PB
http://www.purebasic.com/french/documen ... mulas.html
(y'a tout dans PB, tout, la doc est magique)

:wink:
Mesa
Messages : 1126
Inscription : mer. 14/sept./2011 16:59

Re: SpriteRotation et boite englobante

Message par Mesa »

En reprenant le code de Stargate http://www.purebasic.fr/english/viewtop ... =4&t=65171

Il faut tout recalculer:

Code : Tout sélectionner

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

Procedure CalculCoin(X.f, Y.f, Width.f, Height.f, Angle.f, ScreenX.f, ScreenY.f)
  Protected Cos.f = Cos(Radian(Angle))
  Protected Sin.f = Sin(Radian(Angle))
  Protected.f x1,y1, x2,y2, x3,y3, x4,y4
  x1=(X*Cos-Y*Sin) + ScreenX
  y1=(X*Sin+Y*Cos) + ScreenY
  x2=((X+Width)*Cos-Y*Sin )+ ScreenX
  y2=((X+Width)*Sin+Y*Cos) + ScreenY
  x3=((X+Width)*Cos-(Y+Height)*Sin ) + ScreenX
  y3=((X+Width)*Sin+(Y+Height)*Cos ) + ScreenY
  x4=(X*Cos-(Y+Height)*Sin ) + ScreenX
  y4=(X*Sin+(Y+Height)*Cos) + ScreenY
  
  If StartDrawing(ScreenOutput())
    Circle(x1, y1, 2,  $0000ff)
    Circle(x2, y2, 2,  $0000ff)
    Circle(x3, y3, 2,  $0000ff)
    Circle(x4, y4, 2,  $0000ff)
    LineXY(x1, y1,x2, y2, $00ffff)
    LineXY(x2, y2,x3, y3, $00ffff)
    LineXY(x3, y3,x4, y4, $00ffff)
    LineXY(x1, y1,x4, y4, $00ffff)
    StopDrawing()
  EndIf
  
EndProcedure

InitSprite()

Enumeration
  #Window
  #Sprite
  #Font
EndEnumeration

LoadFont(#Font, "Arial", 24)

OpenWindow(#Window, 0, 0, 800, 600, "ScreenTitle", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(#Window), 0, 0, WindowWidth(#Window), WindowHeight(#Window), 0, 0, 0)

CreateSprite(#Sprite, 200, 50)
If StartDrawing(SpriteOutput(#Sprite))
  DrawingFont(FontID(#Font))
  Box(0, 0, OutputWidth(), OutputHeight(), $808080)
  DrawingMode(#PB_2DDrawing_Transparent)
  DrawText(0, 0, "Pure Basic", $FFFFFF)
  StopDrawing()
EndIf

ClearScreen(0)

SpriteTransformation(#Sprite, 0, 0, 200, 50, 0)
DisplaySprite(#Sprite, 200, 100)
CalculCoin(0, 0, 200, 50, 0, 200, 100)


SpriteTransformation(#Sprite, 0, 0, 200, 50, 45)
DisplaySprite(#Sprite, 400, 200)
CalculCoin(0, 0, 200, 50, 45, 400, 200)

SpriteTransformation(#Sprite, 50, 20, 100, 25, -45)
DisplaySprite(#Sprite, 600, 300)
CalculCoin(50, 20, 100, 25, -45, 600, 300)


FlipBuffers()

Repeat
  
  Repeat
    
    Select WindowEvent()
      Case #PB_Event_CloseWindow
        End
      Case #Null
        Break
    EndSelect
    
  ForEver
  
  
  
ForEver
M.
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: SpriteRotation et boite englobante

Message par blendman »

salut

Bon, j'y suis parvenu en trouvant un code Typhon (d'après un code comtois) qui fonctionnait, mais ne marchait pas avec mon exemple, car il prenait une valeur un peu hasardeuse pour créer la boite, et cette valeur se trouvait être l'angle d'un des cotés du triangle format la moitié de ma boite (car un rectangle, c'est effectivement formé de 2 triangles ^^).

Voici donc en gros le code final qui fonctionne nickel (je vais le poster dans trucs & astuces ^^):

Code : Tout sélectionner

 

If InitSprite() = 0 Or InitKeyboard()=0 Or UsePNGImageDecoder() = 0 Or UseJPEGImageDecoder() = 0
    MessageRequester("Error","DirectX 7+ is needed.",0)
    End
EndIf

OpenWindow(0,0,0,800,600,"Sprite bounding box",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
OpenWindowedScreen(WindowID(0),0,0, 800, 600, 0, 0, 0)

file$ = OpenFileRequester("Load image to sprite","","PNG (*.png)|*.png|JPG(.jpg,.jpeg)|*.jpg;*.jpeg)",0)
If file$ <> ""
    If LoadSprite(0,File$,#PB_Sprite_AlphaBlending)
        w = SpriteWidth(0)
        h = SpriteHeight(0)
    Else
        MessageRequester("Error","Unable to load the image "+file$)
        End
    EndIf
    
EndIf
x = 100
y = 100
#DEG = #PI/180

Repeat
    
    
    Repeat
        
        event = WaitWindowEvent(1)
        If event = #PB_Event_CloseWindow
            End
        EndIf
        
    Until event =0
    
    
    
    angle +1
    If angle > 360
        angle = 0
    EndIf
    
    R = Sqr(w*w+h*h)/2 ; demi diagonal in center
    
    u.f = Degree(ATan(h/w))
    
    X1=X+w/2+R*Cos((Angle-u)*#DEG)
    Y1=Y+h/2+R*Sin((Angle-u)*#DEG)
    X2=X+w/2+R*Cos((Angle+u)*#DEG)
    Y2=Y+h/2+R*Sin((Angle+u)*#DEG) 
    X3=X+w/2+R*Cos((Angle-180+u)*#DEG)
    Y3=Y+h/2+R*Sin((Angle-180+u)*#DEG)
    X4=X+w/2+R*Cos((Angle+180-u)*#DEG)
    Y4=Y+h/2+R*Sin((Angle+180-u)*#DEG)
    
    
    ClearScreen(RGB(120,120,120))
    RotateSprite(0,angle,0)
    DisplayTransparentSprite(0,x,y)
    
    StartDrawing(ScreenOutput())
        
    LineXY(X1,Y1,X2,Y2)
    LineXY(X2,Y2,X4,Y4)
    LineXY(X3,Y3,X1,Y1)
    LineXY(X3,Y3,X4,Y4)
        
    
    StopDrawing()
    
    Delay(1)
    
    FlipBuffers()
       
    If ExamineKeyboard()
    EndIf
        
Until KeyboardPushed(#PB_Key_Escape) 

EDIT : ah, merci Mesa je n'avais pas vu ton code, mais il devrait m'être bien utile aussi ;)
Répondre