Gadget2D

Programmation avancée de jeux en PureBasic
jem
Messages : 18
Inscription : lun. 26/sept./2011 9:02

Gadget2D

Message par jem »

Lien :
http://www.megaupload.com/?d=LHA4EH1I

Ajout :
Gadget2D_WINDOW
gestion des gadgets parents / enfants


--------------------------------------------------------

Bonjour,
je reprend sur un nouveau topique la suite de ce thread : http://www.purebasic.fr/french/viewtopi ... =2&t=12350

Pour résumer, l'idée est de faire une blibiotheque de Gadget fonctionant en mode "Screen" ( d'ou l'appelation Gadget2D ), le plus identique possible à la bibliotheque de gadget "standard" fournit avec PB.

Je suis actuelement en train de poser les "bases" du code que je vais mettre à disposition dès que cette "base" sera finit ( dans la semaine ). Afin que tout le monde puisse y mettre son grain de sel

Actuelement j'ai uniquement un Button Gadget, et le chargement d'un "Design" sous forme d'un fichier .PNG ( plutot que BMP pour la gestion du canal Alpha ) et .PREF. J'expliquerai le fonctionnement plus tard et on le modifira en fonction des avis de tout le monde.

Pour finir ma "base", il me reste à écrire le "Texte" dans le bouton.
Je sais comment faire, je me pose juste des questions sur la meilleur façon de le faire ou des idées de méthode pour "optimiser" le code

Plutot que d'ecrire le Text dans le sprite du bouton, j'ai opté pour une solution qui résoud une "complication", et permet d'activer une option que je trouve plaisante. Je m'explique :

Les Gadget2Ds gèrent l'opacité pour l'affichage.
Le texte peut être écrit directement dans le sprite du gadget, il prendra donc l'opacité du gagdet. Pour changer le texte du gadget il faut "redessiner" TOUT le gadget ou alors pondre un algo qui va se charger d'effacer le texte précédent en se servant de la prétendu taille du texte ( avec TextWidth() et TextHeight() ). Pas infaisable, mais pas simple. D'autant plus que le "Design" supporte un fond d'écran qui peut etre si on le souhaite un motif répétable.

Autre méthode : on creer un nouveau Sprite juste pour le texte, de la meme taille que son gadget et qui va se superposer à l'affichage. Le fond sera transparent, le texte sera réécrit facilement, en "redessinant" le sprite en le remplissant avec la couleur tranparente ( Box() ).
Option sympa : on va pouvoir gérer le niveau d'opacité du texte différent du gadget lui meme, et donc avoir par exemple, un gadget translucide avec un texte avec la couleur vif/pleine.
Cela rajoute un sprite en mémoire, et donc consomme un peu plus de mémoire ... de plus à l'affichage on devra afficher 2 sprites pour chaque gadget, donc perte de FPS ( peut etre minime ou pas , mais perte quand meme ). Une alternative pourrait être de stocker un 3em sprite pour chaque gadget , 0 => Border + Fond , 1 = Texte , 2 ==> Mixe des 2 pour affichage d'un sprite unique.

Ce qui m'ennuie c'est de pondre une procédure/méthode/algo pour effacer le texte d'un gadget sans avoir à tout redessiner, bien que cela soit aussi une possibilité, peut etre mème la plus simple à coder.

Je n'ai surement pas penser à tout.

Votre avis, les pro du PB ? Vous, vous feriez comment ?
Dernière modification par jem le lun. 21/nov./2011 15:00, modifié 2 fois.
PureBasic V4.60 RC2 x86 | Windows 7
jem
Messages : 18
Inscription : lun. 26/sept./2011 9:02

Re: Gadget2D

Message par jem »

Voici la base du projet Gadget 2D :

[Lien dans le post initial]

Le fichier Zip contient :

gadget2D.pbp -le fichier de projet Pb
main.pb -le fichier contenant la boucle principal du programme de test d'affichage
_source\Gadget2D.pbi -Le fichier principal de la bibliotheque
_source\Gadget2D_Button.pbi - les procedures pour le ButtonGadget
_source\Gadget2D_TextGadget.pbi -les procédures pour le TextGadget
Design\Base0\Design.png -le fichier Bitmap contenant le Design Visuel
Design\Base0\Design.pref -le fichier de preférence contenant les coordonnés des élément du Design
Design\Base0\Cursor.bmp -le fichier imlage du curseur de la souris


2 Gadgets sont pour le moment codés : le button Gadget et le TextGadget.
Ils fonctionnent de la mème façon que les Gadgets PB Standard ( meme syntaxe , meme constantes pour les Options ), à une exception pret : un parametre optionel supplémentaire pour chaque gadget à la fin de la déclaration de ceux ci, permetant de gérer "l'opacité" du gadget lors de l'affichage ( fait avec DisplayTranslucentSprite(#Sprite, x, y, Intensité) )

Code : Tout sélectionner

Gadget2D_TextGadget(GadgetID.l,width.l,height.l,positionX.l,positionY.l,Text.s,Options.q=0,Opacity.a=255)
J'ai utiliser les memes nom de procedure en rajoutant le prefixe : Gadget2D_

J'ai pour le moment coder que les procedures annexes servant à ces 2 gadgets :
GetGadgetText()
SetGadgetText()
GetGadgetState()
SetGadgetState()
SetGadgetColor()
GetGadgetColor()

Le Design fonctionne pour le moment de la façon suivante :

Il comporte 9 élements de chaque "état" d'affichage :

Code : Tout sélectionner

Global Dim Gadget2D_DesignElementItem.s(8)
  Gadget2D_DesignElementItem(0)="Background"
  Gadget2D_DesignElementItem(1)="Corner_Left_Up"
  Gadget2D_DesignElementItem(2)="Line_Up"
  Gadget2D_DesignElementItem(3)="Corner_Right_Up"
  Gadget2D_DesignElementItem(4)="Line_Right"
  Gadget2D_DesignElementItem(5)="Corner_Right_Down"
  Gadget2D_DesignElementItem(6)="Line_Down"
  Gadget2D_DesignElementItem(7)="Corner_Left_Down"
  Gadget2D_DesignElementItem(8)="Line_Left"
les 4 états actuel sont :

Code : Tout sélectionner

  #GADGET2D_DISPLAY_NONE      ;=-1 ==> 4em état servant a ne pas afficher le gadget, donc pas besoin de Design
  #GADGET2D_DISPLAY_NORMAL    ==> affichage standard
  #GADGET2D_DISPLAY_HOVER      ==> la souris survole le gadget
  #GADGET2D_DISPLAY_CLIKED      ==> click sur le gadget ou gadget activé   ( je viens de m'apercevoir de la faute : manque le C de cliCked , je corrigerais dans une autre version - cela ne pose pas de probleme sur le fonctionnement actuel , la faute est partout :) )
On peut charger plusieurs Design différent et affiche chaque gadget avec son propre Design ( prévu mais non testé )

Vous remarquerez au passage que moi le Design graphique ça fait 2 :D
Le fichier Design.pref sert a indiquer les coordonnées et dimension de chaque élément dans le fichier contenant les images des élements
On pourrait se passer du fichier et faire un traitement automatique de l'image pour rechercher les éléments. L'utilisation d'un fichier simplifie énormément le code du chargement des elements en mémoire
On pourrait creer un "éditeur" de Design pour faire le fichier de "pref"
La taille des elements est libre
Le background supporte des gadgets supporte une image "tilable" ( répétable )


Il reste beaucoup de travail.
On peut s'occuper de rajouter les élements les uns apres les autres. Tout le monde peut participer s'il le désir.

Je suis ouvert à toute discussion sur de meilleur façon de coder les gadget.
Par exemple , j'aurais aimé que chaque fichier .pbi contenant le code des gadgets gèrent aussi leur propre code d'evenement,plutot que centralisé ça dans le fichier "_source\Gadget2D.pbi" , mais je ne vois pas comment organiser ça au niveau du code.
On peut totalement changer la façon de fonctionner du Design

Les états d'affichage et la façon de les stoker vont surement changer, car cela ne correspondra pas à l'affichage d'autres gadgets ( comme le gadget checkBox par exemple qui comporte d'autre état d'affichage )
L'idée principal est d'essayer au maximum de "copier" la structure et la syntaxe des gadgets PB standard, mais je me rend compte que certain manque important à mes yeux pourrait être combler
Par exemple le composant checkBox ne comporte pas d'option d'allignement du texte à gauche de la case à cocher, et ça c'est moche :) , on peut facilement la rajouter dans notre bibliotheque.

Autre exemple : je modifirai bien le Gadget "container", pour lui donner la possibilité d'être affichable (avec le Design) et déplaçable à l'ecran ( se comporter comme une fenetre contenant d'autre gadget )

Je n'ai pas encore réfléchi comment intégré une police de caractère.


enjoy !
Dernière modification par jem le lun. 21/nov./2011 14:23, modifié 1 fois.
PureBasic V4.60 RC2 x86 | Windows 7
Avatar de l’utilisateur
blendman
Messages : 2017
Inscription : sam. 19/févr./2011 12:46

Re: Gadget2D

Message par blendman »

salut

J'ai regardé ton exemple et c'est pas mal.
Juste comme ça, personnellement, au lieu de faire ça :

Code : Tout sélectionner

If Gadget2D_GetGadgetState(#GUI_BUTTON_TOGGLE)
   Gadget2D_SetGadgetState(#GUI_BUTTON_TOGGLE,0)
Else
    Gadget2D_SetGadgetState(#GUI_BUTTON_TOGGLE,1)
EndIf
Je fais ça :

Code : Tout sélectionner

Gadget2D_SetGadgetState(#GUI_BUTTON_TOGGLE,1-Gadget2D_GetGadgetState(#GUI_BUTTON_TOGGLE))
En gros, pour inverser une variable (qui vaut 0 ou 1), le plus simple est de faire :

Code : Tout sélectionner

variable = 1-variable
Sinon, j'ai remarqué que tu avais inversé dans ta procédure la position et la taille du bouton :

Code : Tout sélectionner

Gadget2D_ButtonGadget(GadgetID.l,width.l,height.l,positionX.l,positionY.l,Text.s,Options.q=0,Opacity.a=255) 
En général, en pure c'est d'abord la position, puis la taille ;).

Sinon, c'est bien cool tout ça.
Avatar de l’utilisateur
Ar-S
Messages : 9472
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: Gadget2D

Message par Ar-S »

Je me permets d'ajouter une toute petite contribution.
Une 1ere esquisse de fonction permettant de créer un carré arrondi.
ARS_2DRoundBox(numerosprite,taille,couleur)
Voilà une première version avec des couleurs différentes histoire que vous visualisiez la technique.

Code : Tout sélectionner

; Creation de boite carré arrondie.
; ARS_2DRoundBox(numerosprite,taille,couleur)
; par Ar-S / nov 2011 / PB 4.60 x86

Global Lsprite = 100 ; Dimensions du carré

InitSprite()

Procedure ARS_2DRoundBox(numerosprite,taille,couleur)
  ; ARS_2DRoundBox v0.1 
  
  Rayon = taille/10/2
  Carre1H = taille - Rayon
  Carre1L = taille - Rayon * 2
  
  Carre2H = taille - Rayon * 3
  Carre2L = taille
  
  CreateSprite(numerosprite, taille,taille)
  If StartDrawing(SpriteOutput(numerosprite))
      Box(Rayon,0,Carre1L,Carre1H,couleur)
      Box(0,Rayon,Carre2L,Carre2H,#Green)
      
      Circle(Rayon , Rayon , Rayon , #red) ; haut gauche
      Circle(taille - Rayon , Rayon , Rayon , #red) ; haut droit
      Circle(taille - Rayon, taille - (Rayon * 2)-1, Rayon, #red) ; bas droit
      Circle(Rayon, taille - (Rayon * 2)-1, Rayon, #red) ; bas gauche
      
    StopDrawing()
  Else
    ProcedureReturn 0
  EndIf
EndProcedure


;fenêtre
Lfenetre = 400 : Hfenetre = 600
PosWinX = 649 : PosWinY = 145

If OpenWindow(0, PosWinX, PosWinY, Lfenetre, Hfenetre, "Window", #PB_Window_SystemMenu|#PB_Window_TitleBar|#PB_Window_ScreenCentered)
  ButtonGadget(0, Lfenetre - 100, Hfenetre - 20, 100, 20, "Quitter")
  TextGadget(1,Lsprite+50,Hfenetre-15,150,15,"BoOm : "+Str(cogne))
  If OpenWindowedScreen(WindowID(0), 0, 0, Lfenetre, Hfenetre-20, 0, 0, 0)

    ARS_2DRoundBox(1,Lsprite,$00CCFF)
    
  Else
    Debug "Error openwindowsscreen"
  EndIf 
Else
  Debug "Error openwindow"
EndIf

;{- Event loop

Repeat
  
  ; ---------------------------
  ; Event gadgets et fenêtre
  ; ---------------------------
  Repeat
    event = WindowEvent()
    
    Select event 
      Case #PB_Event_Gadget
        Select EventGadget() 
          Case 0 ; ; bouton quitter
            End
        EndSelect  
        
      Case #PB_Event_CloseWindow
        End 
    EndSelect
  Until event = 0
  
  ; ---------------------------
  ; Event fenêtre graphique
  ; ---------------------------
  
  FlipBuffers() 
  ClearScreen(RGB(0, 0, 0))
  
  DisplaySprite(1, (Lfenetre/2)-(Lsprite/2), (Hfenetre/2)-(Lsprite/2)) ; positionnement du sprite au centre
  
  
ForEver

et voilà le rendu tel qui est vraiment.

Code : Tout sélectionner

; Creation de boite carré arrondie.
; ARS_2DRoundBox(numerosprite,taille,couleur)
; par Ar-S / nov 2011 / PB 4.60 x86

Global Lsprite = 100 ; Dimensions du carré

InitSprite()

Procedure ARS_2DRoundBox(numerosprite,taille,couleur)
  ; ARS_2DRoundBox v0.1 
  
  Rayon = taille/10/2
  Carre1H = taille - Rayon
  Carre1L = taille - Rayon * 2
  
  Carre2H = taille - Rayon * 3
  Carre2L = taille
  
  CreateSprite(numerosprite, taille,taille)
  If StartDrawing(SpriteOutput(numerosprite))
      Box(Rayon,0,Carre1L,Carre1H,couleur)
      Box(0,Rayon,Carre2L,Carre2H,couleur)
      
      Circle(Rayon , Rayon , Rayon , couleur) ; haut gauche
      Circle(taille - Rayon , Rayon , Rayon , couleur) ; haut droit
      Circle(taille - Rayon, taille - (Rayon * 2)-1, Rayon, couleur) ; bas droit
      Circle(Rayon, taille - (Rayon * 2)-1, Rayon, couleur) ; bas gauche
      
    StopDrawing()
  Else
    ProcedureReturn 0
  EndIf
EndProcedure


;fenêtre
Lfenetre = 400 : Hfenetre = 600
PosWinX = 649 : PosWinY = 145

If OpenWindow(0, PosWinX, PosWinY, Lfenetre, Hfenetre, "Window", #PB_Window_SystemMenu|#PB_Window_TitleBar|#PB_Window_ScreenCentered)
  ButtonGadget(0, Lfenetre - 100, Hfenetre - 20, 100, 20, "Quitter")
  TextGadget(1,Lsprite+50,Hfenetre-15,150,15,"BoOm : "+Str(cogne))
  If OpenWindowedScreen(WindowID(0), 0, 0, Lfenetre, Hfenetre-20, 0, 0, 0)
    
    ARS_2DRoundBox(1,Lsprite,$00CCFF)
    
  Else
    Debug "Error openwindowsscreen"
  EndIf 
Else
  Debug "Error openwindow"
EndIf

;{- Event loop

Repeat
  
  ; ---------------------------
  ; Event gadgets et fenêtre
  ; ---------------------------
  Repeat
    event = WindowEvent()
    
    Select event 
      Case #PB_Event_Gadget
        Select EventGadget() 
          Case 0 ; ; bouton quitter
            End
        EndSelect  
        
      Case #PB_Event_CloseWindow
        End 
    EndSelect
  Until event = 0
  
  ; ---------------------------
  ; Event fenêtre graphique
  ; ---------------------------
  
  FlipBuffers() 
  ClearScreen(RGB(0, 0, 0))
  
  DisplaySprite(1, (Lfenetre/2)-(Lsprite/2), (Hfenetre/2)-(Lsprite/2)) ; positionnement du sprite au centre
  
  
ForEver

~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
jem
Messages : 18
Inscription : lun. 26/sept./2011 9:02

Re: Gadget2D

Message par jem »

blendman a écrit :

Code : Tout sélectionner

Gadget2D_SetGadgetState(#GUI_BUTTON_TOGGLE,1-Gadget2D_GetGadgetState(#GUI_BUTTON_TOGGLE))

Code : Tout sélectionner

variable = 1-variable
Tiens sympas, j'avais jamais pensé à ça. Dans cet exemple effectivement ça simplifie le code. Je vais implémenter ça
blendman a écrit : Sinon, j'ai remarqué que tu avais inversé dans ta procédure la position et la taille du bouton :

Code : Tout sélectionner

Gadget2D_ButtonGadget(GadgetID.l,width.l,height.l,positionX.l,positionY.l,Text.s,Options.q=0,Opacity.a=255) 
En général, en pure c'est d'abord la position, puis la taille ;).
Aye oui, je n'avais pas vu ça, merci , je vais corriger ça tout de suite


@Ar-S
Quel est l'apport de ta procédure par rapport à la procedure native de PB RoundBox() ?
PureBasic V4.60 RC2 x86 | Windows 7
Avatar de l’utilisateur
Ar-S
Messages : 9472
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: Gadget2D

Message par Ar-S »

Rien si ce n'est que j'avais oublié cette commande et que je suis une grosse quenelle :mrgreen:
A terme ce sera tout de même logiquement un 2DbuttonGadget. Mais c'est sur que j'utiliserai la commande native pour la forme du bouton.
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
jem
Messages : 18
Inscription : lun. 26/sept./2011 9:02

Re: Gadget2D

Message par jem »

Nouvelle version : [Lien dans le premier post de ce topic]

-Ajout du composant Gadget2D_Window
-gestion des parents / enfants ( utile pour certain gadget comme Gadget2D_Window , et eventuekement plus tard Gadget2D_Container ( plus trop util )
-prise en compte des remarques concernant l'ordre des parametres dans les déclarations de procédure

---------------------------

J'avais prévu de faire modifier le comportement du gadget CONTAINER PB natif.
Après réflexion, je me suis dit que je pouvais laisser ce composant libre ( le nom disponible ) et creer un nouveau nom qui reflèterai plus le comportement que j'avais en tète.
Il s'agit ici de créer un container pouvant être transparent ou pas, qui peut contenir d'autres gadgets ( qui seront afficher seulement si le parent est afficher, qu'il soit tranparent ou non ) et déplaçable selon le choix lors de la création du gadget, bref : une fenètre.

Code : Tout sélectionner

resultat=Gadget2D_WindowGadget(GadgetID.l,positionX.l,positionY.l,width.l,height.l,Text.s="",Options.q=0,Opacity.a=255)
Les options disponibles sont les suivantes

Code : Tout sélectionner

#GADGET2D_OPTIONS_WINDOW_TITLE_CENTER = %00000001 
#GADGET2D_OPTIONS_WINDOW_TITLE_RIGHT = %00000010
#GADGET2D_OPTIONS_WINDOW_NO_TITLE = %00000100
#GADGET2D_OPTIONS_WINDOW_DRAGGABLE = %00001000
#GADGET2D_OPTIONS_WINDOW_NODESIGN = %00010000

Pour compléter la gestion des Gadget2D_Event() j'ai du modifier le stockage en mémoire des gadgets.
Je stock les gadgets dans une "Map" pour un accès rapide individuel.
Pour gérer les fenètres déplaçables, on doit gérer une notion de "profondeur" lorsque 2 éléments ce surperose.
Je suis donc passé par une gestion d'ordre d'insertion des éléments avec une LinkedList qui contient simplement l'ID du gadget.

pour le "Display()" des gadgets , je lis la liste dans l'ordre d'insertion, ainsi les premiers élements sont "sous" les élements suivants lors de l'affichage
pour la gestion des "Event()" je lis la liste dans le sens inverse, les derniers gadgets sont prioritaires pour la gestion des evenements si 2 éléments se chevauchent

Je me retrouve donc avec 2 variables de stockage :
- la Map qui contient les 2 élement avec leur structure
- une LinkedList, qui contient juste l'ID du gadget, pour avoir leur Ordre de création et la possibilité de lire ou de trier l'odre des gadgets.

Ce n'est pas très "élégant", mais je ne vois pas d'autre solution pour gérer l'accès aux gadgets individuelement et tres rapidement, et gérer un "ordre" pour ces mèmes gadgets.
Techniquement parlant on pourrait utiliser un tableau ( Array ) pour gérer la list d'insertion des gadgets, mais si on veux insérer un gadget à un endroit dynamiquement autre qu'après dernier élément ( pk pas hein !! ) cela devient plus facile de gérer ça avec une LinkedList plutot qu'un tableau dont il faudrait écrire des routines pour déplacer tous les élements lors d'une insertion.

Si vous voyez une méthode plus élégante (en utilisant uniquement des procédures Natif à PB) pour gére une liste, avec accès rapide à un élément et gestion de l'ordre, je suis preneur :)

Comme d'habitude je reste ouvert à toute discussion sur le sujet.

Prochain étape, le gadget checkBox.
Et j'ai déja des remarques et besoin de vos avis.
Les gadgets standard checkBox de PB ne me semble pas être adéquate pour une utilisation 2D.
Nous ne pouvons pas régler leur "taille réelle" et certaines options ne me semble pas vraiment utile, d'autres manquantes.
Voila les modifications que j'apporterai bien :
-la taille ( width et height ) du gadget servirai à définir la "Taille" de la case à cocher
-l'intégration d'une option "GADGET2D_OPTION_CHECKBOX_ALIGN_LEFT" pour faire afficher le texte à gauche de la case à cocher ( "droite" serait par défault, "centre" disparaitrait)

Si vous vous sentez concerné par le sujet, tout avis est bon à prendre.

enjoy!
PureBasic V4.60 RC2 x86 | Windows 7
Répondre