Sprite, Rotation et boite englobante (bounding box)

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Sprite, Rotation et boite englobante (bounding box)

Message par blendman »

salut

voici un petit code pratique si on veut afficher une boite englobante (bouding box) pour un sprite :

Code : Tout sélectionner

; mars 2016
; d'après un code de typhon lui-même d'après un code comtois
; modifié par blendman pour prendre en compte l'angle du triangle rectangle interne, pour que ça fonctionne avec tous les sprites.
; attention la rotation du sprite est centrée en w/2,h/2 dans cet example

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()
       
    FlipBuffers()
   
    If ExamineKeyboard()
    EndIf
        
Until KeyboardPushed(#PB_Key_Escape) 

Et pour des rotations de sprites libres (non centrées en w/2,h/2), d'après un code de stargate, modifié par Mesa :

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
Mesa
Messages : 1126
Inscription : mer. 14/sept./2011 16:59

Re: Sprite, Rotation et boite englobante (bounding box)

Message par Mesa »

Juste pour le fun, on peut ajouter une petite anim.
(Comme amélioration, il vaudrait mieux dessiner dans un sprite puis l'afficher plutôt que de dessiner sur le screen)

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
  
  SpriteTransformation(#Sprite, -100, -25, 100, 25, ElapsedMilliseconds()) 
  DisplaySprite(#Sprite, 600, 100) 
  CalculCoin(-100, -25, 100, 25, ElapsedMilliseconds(), 600, 100)
  FlipBuffers() 
  Delay(1)
  
  
ForEver

M.
Avatar de l’utilisateur
falsam
Messages : 7324
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Sprite, Rotation et boite englobante (bounding box)

Message par falsam »

blendman a écrit :voici un petit code pratique si on veut afficher une boite englobante (bouding box) pour un sprite :
je pense que tu as un peu compliqué le code : Tu peux dessiner ta boite englobante directement dans le sprite sans faire tous ces calculs.

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

Repeat
  Repeat
    event = WaitWindowEvent(1)
    If event = #PB_Event_CloseWindow
      End
    EndIf
  Until event = 0
  
  ClearScreen(RGB(120,120,120))
  RotateSprite(0, 1, #PB_Relative)
  DisplayTransparentSprite(0,x,y)
  
  StartDrawing(SpriteOutput(0))
  DrawingMode(#PB_2DDrawing_AllChannels | #PB_2DDrawing_Outlined)
  Box(0, 0, SpriteWidth(0), SpriteHeight(0), RGBA(255, 0, 0, 255))
  StopDrawing()
  
  FlipBuffers()
  
  If ExamineKeyboard()
  EndIf
  
Until KeyboardPushed(#PB_Key_Escape) 
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7324
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Sprite, Rotation et boite englobante (bounding box)

Message par falsam »

@Mesa: Bien ton code et ça fonctionne aussi avec des images transparentes. Malgré ça tu n'aura qu'un 8/10 :mrgreen:
Mesa a écrit :Comme amélioration, il vaudrait mieux dessiner dans un sprite puis l'afficher plutôt que de dessiner sur le screen
C'est pour ça que tu as fait exactement le contraire de ce que tu dis ?^^

@Spock: Tu va encore te fâcher et croire que je te cherche : Mais ta note sera de 0 car tu es HS. Tu dessines des rectangles et des cercles sans aucun rapport avec le code de blendman. Mesa a fait l'effort l'effort de créer un sprite et d'ajouter un bounding-Box.
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
falsam
Messages : 7324
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Sprite, Rotation et boite englobante (bounding box)

Message par falsam »

Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: Sprite, Rotation et boite englobante (bounding box)

Message par blendman »

@Falsam : C'est vrai que ton code est plus simple. Par contre, j'avais besoin de récupérer les sommets du rectangle pour y afficher des anchors par exemple.
Comme dans photoshop/gimp, pour redimensionner un sprite ou faire une rotation de ce sprite ^^.
A moins que tu aies une idée pour faire ça avec ta technique, car il me faut les sommets du sprite après rotation (pour pouvoir les bouger par exemple) :D.


@spock : merci pour tes codes avec les rectangles, effectivement, on peut faire comme ça aussi. Par contre, c'est plus délicat, car il faut tout de même trouver la position du premier sommet du sprite, en fonction de sa rotation ;).
Avatar de l’utilisateur
falsam
Messages : 7324
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Sprite, Rotation et boite englobante (bounding box)

Message par falsam »

blendman a écrit :Par contre, j'avais besoin de récupérer les sommets du rectangle pour y afficher des anchors par exemple.
Juste l'affichage des points d'ancrage.

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

Repeat
  Repeat
    event = WaitWindowEvent(1)
    If event = #PB_Event_CloseWindow
      End
    EndIf
  Until event = 0
  
  ClearScreen(RGB(120,120,120))
  RotateSprite(0, 45, #PB_Absolute)
  DisplayTransparentSprite(0,x,y)
  
  ;Dessin du cadre de redimensionnement
  StartDrawing(SpriteOutput(0))
  DrawingMode(#PB_2DDrawing_AllChannels | #PB_2DDrawing_Outlined)
  Box(0, 0, SpriteWidth(0), SpriteHeight(0), RGBA(255, 0, 0, 255))
  
  ;Dessin des points d'ancrages
  DrawingMode(#PB_2DDrawing_AllChannels)
  Box(0, 0, 8, 8, RGBA(255, 0, 0, 255)) ;Coin Haut Gauche    
  Box(0, SpriteHeight(0)-8, 8, 8, RGBA(255, 0, 0, 255)) ;Coin Bas Gauche
  Box(SpriteWidth(0)-8, 0, 8, 8, RGBA(255, 0, 0, 255))  ;Coin Haut Droit
  Box(SpriteWidth(0)-8, SpriteHeight(0)-8, 8, 8, RGBA(255, 0, 0, 255)) ;Coin Bas Droit
  
  StopDrawing()
  
  FlipBuffers()
  
  If ExamineKeyboard()
  EndIf
  
Until KeyboardPushed(#PB_Key_Escape)
PS: Dans ton premier code tu n'affiches pas les points d'ancrage.
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: Sprite, Rotation et boite englobante (bounding box)

Message par blendman »

En fait, c'est les afficher et pouvoir les modifier que j'aimerai faire ;)

Dans mon 1er code, j'ai leur coordonnées (x1y1,x2y2, etc..), donc je peux mettre facilement un circle(), box(), etc... et ensuite vérifier si je suis au dessus avec la souris pour les déplacer.
Mesa
Messages : 1126
Inscription : mer. 14/sept./2011 16:59

Re: Sprite, Rotation et boite englobante (bounding box)

Message par Mesa »

@falsam: C'est pour ça que tu as fait exactement le contraire de ce que tu dis ?^^
Vi vi, c'est toujours après avoir fait la bêtise qu'on s'en rend compte :|

Un petit peu comme toi quand tu dessines un sprite indéfiniment dans une boucle inutilement :wink:

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","","All |*.png;*.jp*|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

;Dessin du cadre de redimensionnement
	StartDrawing(SpriteOutput(0))
	DrawingMode(#PB_2DDrawing_AllChannels | #PB_2DDrawing_Outlined)
	Box(0, 0, SpriteWidth(0), SpriteHeight(0), RGBA(255, 0, 0, 255))
	
	;Dessin des points d'ancrages
	DrawingMode(#PB_2DDrawing_AllChannels)
	Box(0, 0, 8, 8, RGBA(255, 0, 0, 255)) ;Coin Haut Gauche    
	Box(0, SpriteHeight(0)-8, 8, 8, RGBA(255, 0, 0, 255)) ;Coin Bas Gauche
	Box(SpriteWidth(0)-8, 0, 8, 8, RGBA(255, 0, 0, 255))  ;Coin Haut Droit
	Box(SpriteWidth(0)-8, SpriteHeight(0)-8, 8, 8, RGBA(255, 0, 0, 255)) ;Coin Bas Droit
	StopDrawing()
	
x = 100
y = 100

Repeat
  Repeat
    event = WaitWindowEvent(1)
    If event = #PB_Event_CloseWindow
      End
    EndIf
  Until event = 0
  
  ClearScreen(RGB(120,120,120))
  RotateSprite(0, 1, #PB_Relative);
  DisplayTransparentSprite(0,x,y)
  
  
  
  FlipBuffers()
  
  If ExamineKeyboard()
  EndIf
  
Until KeyboardPushed(#PB_Key_Escape) 
Comme ça, on gagne en vitesse et on évite le scintillement. :)


@Blendman
Voici un début de code qui peut t'intéresser. J'ai la flemne de le finir...
Survol le coin haut et gauche du rectangle gris, remarque la couleur du curseur et clique pour voir le résultat. T'as "plus qu'à" utiliser transformsprite() pour déformer le rectangle.

Code : Tout sélectionner

; Quelques variables
MargeG = 20 
MargeH = 20 
LargeurEcran = 440 
HauteurEcran = 440 
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))
  Shared.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
; Initialisation du monde 2D
InitSprite()
InitMouse() 

; Ouverture de la fenêtre et de l'écran
OpenWindow(0,0,0,650,480,"Capture/Libération de la souris",#PB_Window_ScreenCentered|#PB_Window_SystemMenu) 
ButtonGadget(1,500,440,120,24,"Cliquez !") 
OpenWindowedScreen(WindowID(0),20,20,LargeurEcran,HauteurEcran,0,0,0) 
#SpriteMouse=0
CreateSprite(#SpriteMouse,10,10)
If StartDrawing(SpriteOutput(#SpriteMouse))
  Box(0, 0, 9, 9, $808080)
  ;DrawingMode(#PB_2DDrawing_Transparent)
  LineXY(0,0,9,9,RGB(255,0,0))
  
  StopDrawing()
EndIf
#SpriteMouse2=1
CreateSprite(#SpriteMouse2,10,10)
If StartDrawing(SpriteOutput(#SpriteMouse2))
  Box(0, 0, 9, 9, $808080)
  ;DrawingMode(#PB_2DDrawing_Transparent)
  LineXY(0,0,9,9,RGB(255,255,0))
  
  StopDrawing()
EndIf
#SpriteRect=2
CreateSprite(#SpriteRect,100,50)
If StartDrawing(SpriteOutput(#SpriteRect))
  Box(0, 0, 99, 99, $808080)
  ;DrawingMode(#PB_2DDrawing_Transparent)
  
  StopDrawing()
EndIf
; Gestion de la fenêtre et de l'écran
Repeat
  
  Repeat ; Gestion de la fenêtre
    Event  = WindowEvent()  
    Select Event 
      Case #PB_Event_Gadget 
        If EventGadget() = 1     ; Si Clic sur le Bouton "Cliquez !"
          MessageRequester("Attention","Bouton cliqué !") 
        EndIf 
      Case #PB_Event_CloseWindow ; Si fermeture de la fenêtre
        End
    EndSelect
    
    ; Affichage de la position de la souris dans la fenêtre
    SetWindowTitle(0, "Capture/Libération de la souris X= " + Str(mx) + " Y= "+ Str(my))
  Until Event =  0 
  
  ; Gestion de la capture de la souris dans l'écran noir
  If inScreen = #True       ; Si la souris est dans l'écran noir...
    If MouseX() > LargeurEcran-2 Or MouseY() > HauteurEcran-2 Or MouseX() < 1 Or MouseY() <1 
      ReleaseMouse(#True)   ; ...et si elle s'approche des bords de l'écran alors on libère la souris
      inScreen = #False 
    EndIf  
  Else                      
    mx = WindowMouseX(0)      ; Sinon, si la souris entre dans l'écran noir...
    my = WindowMouseY(0)
    If mx < LargeurEcran + MargeG And mx > MargeG And my > MargeH And my < MargeH + HauteurEcran                         
      ReleaseMouse(#False)    ; ... alors on capture la souris 
      MouseLocate(mx-MargeG,my-MargeH) 
      inScreen = #True 
    EndIf 
  EndIf 
  
  ; Affichage de l'écran noir
  ClearScreen(0) 
  DisplaySprite(#SpriteRect,100,100)
  CalculCoin(0, 0, 100, 50, 0, 100, 100)
  
  StartDrawing(ScreenOutput()) 
  DrawText(150,200,"Souris relachée") 
  DrawText(180,230,"X= ")
  DrawText(180,260,"Y= ")
  StopDrawing()  
  If inScreen  ; Si la souris est dans l'écran noir... 
    ExamineMouse() 
    MX=MouseX()
    MY=MouseY()
    If Bool(MX>X1-10 And MY<X1+10 And MY>Y1-10 And MY<Y1+10)
      DisplaySprite(#SpriteMouse2,MX, MY)
      If MouseButton(#PB_MouseButton_Left )
        Debug "J'ai la flemme de continuer..."
      EndIf
      
    Else
      DisplaySprite(#SpriteMouse,MX, MY)
    EndIf
    
    StartDrawing(ScreenOutput())
    FrontColor(RGB(255,255,0))
    DrawText(150,200,"Souris capturée" ) 
    DrawText(180,230,"X= "+ Str(MX)) 
    DrawText(180,260,"Y= "+ Str(MY))
    ;DrawText(MouseX(), MouseY(), "["+Chr(164)+"]")
    StopDrawing() 
  EndIf 
  FlipBuffers() 
ForEver

M.
Avatar de l’utilisateur
falsam
Messages : 7324
Inscription : dim. 22/août/2010 15:24
Localisation : IDF (Yvelines)
Contact :

Re: Sprite, Rotation et boite englobante (bounding box)

Message par falsam »

Bien ton code Mesa
Mesa a écrit :Un petit peu comme toi quand tu dessines un sprite indéfiniment dans une boucle inutilement
Taquin le Mesa :wink: J'assume c'est con ce que j'ai fais !

J'ai exécuté ton code.
Debug "J'ai la flemme de continuer..."
ça c'est clair que tu as fait ta faineasse. Les points d'ancrages haut gauche et droite sont capturés mais pas les deux du bas.

En tout cas joli code.
Configuration : Windows 11 Famille 64-bit - PB 6.20 x64 - AMD Ryzen 7 - 16 GO RAM
Vidéo NVIDIA GeForce GTX 1650 Ti - Résolution 1920x1080 - Mise à l'échelle 125%
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: Sprite, Rotation et boite englobante (bounding box)

Message par blendman »

allez, pouf, j'ai continué ton code Mesa, c'est sympa et ça pourra pitet m'être utile qui sait ^^

Code : Tout sélectionner

; Quelques variables
MargeG = 20
MargeH = 20
LargeurEcran = 440
HauteurEcran = 440
xb = 100
yb = 50

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))
  Shared.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
; Initialisation du monde 2D
InitSprite()
InitMouse()

; Ouverture de la fenêtre et de l'écran
OpenWindow(0,0,0,650,480,"Capture/Libération de la souris",#PB_Window_ScreenCentered|#PB_Window_SystemMenu)
ButtonGadget(1,500,440,120,24,"Cliquez !")
OpenWindowedScreen(WindowID(0),20,20,LargeurEcran,HauteurEcran,0,0,0)
#SpriteMouse=0
CreateSprite(#SpriteMouse,10,10)
If StartDrawing(SpriteOutput(#SpriteMouse))
  Box(0, 0, 9, 9, $808080)
  ;DrawingMode(#PB_2DDrawing_Transparent)
  LineXY(0,0,9,9,RGB(255,0,0))
 
  StopDrawing()
EndIf

#SpriteMouse2=1
CreateSprite(#SpriteMouse2,10,10)
If StartDrawing(SpriteOutput(#SpriteMouse2))
  Box(0, 0, 9, 9, $808080)
  ;DrawingMode(#PB_2DDrawing_Transparent)
  LineXY(0,0,9,9,RGB(255,255,0))
 
  StopDrawing()
EndIf

#SpriteRect=2
CreateSprite(#SpriteRect,100,50)
If StartDrawing(SpriteOutput(#SpriteRect))
  Box(0, 0, 99, 99, $808080)
  ;DrawingMode(#PB_2DDrawing_Transparent)
 
  StopDrawing()
EndIf


; Gestion de la fenêtre et de l'écran
Repeat
 
  Repeat ; Gestion de la fenêtre
    Event  = WindowEvent() 
    Select Event
      Case #PB_Event_Gadget
        If EventGadget() = 1     ; Si Clic sur le Bouton "Cliquez !"
          MessageRequester("Attention","Bouton cliqué !")
        EndIf
      Case #PB_Event_CloseWindow ; Si fermeture de la fenêtre
        End
    EndSelect
   
    ; Affichage de la position de la souris dans la fenêtre
    SetWindowTitle(0, "Capture/Libération de la souris X= " + Str(mx) + " Y= "+ Str(my))
  Until Event =  0
 
  ; Gestion de la capture de la souris dans l'écran noir
  If inScreen = #True       ; Si la souris est dans l'écran noir...
    If MouseX() > LargeurEcran-2 Or MouseY() > HauteurEcran-2 Or MouseX() < 1 Or MouseY() <1
      ReleaseMouse(#True)   ; ...et si elle s'approche des bords de l'écran alors on libère la souris
      inScreen = #False
    EndIf 
  Else                     
    mx = WindowMouseX(0)      ; Sinon, si la souris entre dans l'écran noir...
    my = WindowMouseY(0)
    If mx < LargeurEcran + MargeG And mx > MargeG And my > MargeH And my < MargeH + HauteurEcran                         
      ReleaseMouse(#False)    ; ... alors on capture la souris
      MouseLocate(mx-MargeG,my-MargeH)
      inScreen = #True
    EndIf
  EndIf
 
  ; Affichage de l'écran noir
  ClearScreen(0)
  DisplaySprite(#SpriteRect,100,100)
  CalculCoin(xa, ya, xb-xa, yb-ya, 0, 100, 100)
 
  StartDrawing(ScreenOutput())
  DrawText(150,200,"Souris relachée")
  DrawText(180,230,"X= ")
  DrawText(180,260,"Y= ")
  StopDrawing() 
  
  If inScreen  ; Si la souris est dans l'écran noir...
    ExamineMouse()
    MX=MouseX()
    MY=MouseY()
    If MouseButton(#PB_MouseButton_Left )=0
        clic = 0
    EndIf
    
    If Bool(MX>X1-10 And MX<X1+10 And MY>Y1-10 And MY<Y1+10)
        DisplaySprite(#SpriteMouse2,MX, MY)
        If MouseButton(#PB_MouseButton_Left )
            If Clic =0
                clic = 1
                startX = mx -xa
                startY = my -ya
            EndIf
        EndIf
    ElseIf Bool(MX>X3-10 And MX<X3+10 And MY>Y3-10 And MY<Y3+10) 
        DisplaySprite(#SpriteMouse2,MX, MY)
        If MouseButton(#PB_MouseButton_Left )
            If Clic =0
                clic = 2
                startX = mx -xb
                startY = my -yb
            EndIf
        EndIf
    Else
        DisplaySprite(#SpriteMouse,MX, MY)
    EndIf
    
    
    If clic >= 1
        ; Debug "J'ai la flemme de continuer..."
        If clic=1
            xa = mx - startX
            ya = my - startY 
        Else
            xb = mx - startX
            yb = my - startY 
           
        EndIf
        TransformSprite(#SpriteRect,xa,ya,xb,ya,xb,yb,xa,yb)
      EndIf
      
    
;     StartDrawing(ScreenOutput())
;     FrontColor(RGB(255,255,0))
;     DrawText(150,200,"Souris capturée" )
;     DrawText(180,230,"X= "+ Str(MX))
;     DrawText(180,260,"Y= "+ Str(MY))
;     ;DrawText(MouseX(), MouseY(), "["+Chr(164)+"]")
;     StopDrawing()
  EndIf
  FlipBuffers()
ForEver
Répondre