Godot : Listes et Boutons

Créer un diaporama pour se familiariser avec les listes et le système de contrôle.

Un des attraits de Godot réside dans le système de contrôle qu'il intègre. De nombreux nœuds sont mis en place afin que l'utilisateur puisse interagir avec le programme. Boutons, sliders, entrée texte, et autres ScrollBars permettent de développer rapidement de petits utilitaires adaptés aux besoins de chacun.

Le présent tutoriel propose de créer un simple diaporama (ici plus précisément un trombinoscope en l'honneur des acteurs de votre film préféré) connecté à deux boutons afin de comprendre les interactions possibles entre le l'utilisateur et le programme.

Le but de cette page n'étant pas d'expliquer la manipulation des fichiers, les images qui seront utilisées seront déjà redimensionnées à la même échelle, et seront chargés manuellement. J'entends par là qu'un programme plus complexe utiliserait un système de redimensionnement automatique, et également un système d'import des fichiers, mais que pour des raisons pratiques, ce tutoriel ne couvrira pas ces deux points.

Commencez par Créer un projet, aux dimensions 600*600 et intitulé Diaporama.

Téléchargez le dossier d'image et extrayez le dans le dossier data.

Enfin, attachez un script à la scène “main”.

Au poil. La première de nos opérations va être de charger chacune des images au sein du programme. La ligne de code est la suivante :

var   image1   =   preload("chemin/image1")

Le chemin, pour rappel, se décompose comme suit : “ res://dossier1/dossier2/fichier ”.

Dans notre cas, la première image devrait ressembler à ça :

var   image1   =   preload("[[res://data/trombines/wayne.png|  res://data/trombines/wayne.png]]  ")

Créez une variable pour chacune de vos idoles et le code devrait ressembler à ça :

godot_diapo_a.png godot_diapo_a.png

Il s'agit maintenant de créer un Sprite qui va pouvoir afficher ces images. Plutôt que de créer une nouvelle scène, nous allons cette fois créer le Sprite directement via la code. Premièrement, nous allons créer une variable qui permettra de le stocker. Nous pouvons la laisser vide pour l'instant. Elle s'appellera s (pour Sprite).

godot_diapo_b.png godot_diapo_b.png

Nous allons maintenant nous occuper de la régler. Dans la fonction _ready():, nous allons d'abord indiquer à Godot qu'il s'agit d'un Sprite, en utilisant la commande Sprite.new(). .new() permet de rajouter des nœuds à l'intérieur même du code. Nous la réutiliserons tout-à-l'heure.

Puis nous allons la positionner. Au milieu de l'écran sur l'axe des X (à 300 pixels). Sur l'axe des Y, nous souhaiterions qu'il y ait un écart de 10 pixels entre le haut de l'image et le haut de la fenêtre. Un peu de maths : les images font 400 pixels de haut. Comme l'image est centrée sur la position du Sprite, l'image commencera donc 200 pixels au-dessus de sa position, et finira 200 pixels au-dessous. En mettant le Sprite à 210 sur l'axe des Y, l'image commencera donc à 10 pixels du haut de la fenêtre. Nous pouvons donc utiliser la fonction set_pos() comme suit :

s.set_pos(   Vector2(   300,   210   )   )

Ainsi, nous utilisons la fonction set_pos() de s pour le situer à la position Vector2(300,210).

Dans la même logique, nous allons pour l'instant lui attribuer l'image1 grâce à sa fonction set_texture() :

s.set_texture(   image1   )

Enfin, nous l'ajoutons à la scène :

add_child(   s   )

Le code ressemble désormais à cela (n'oubliez pas d'indenter !) :

godot_diapo_c.png godot_diapo_c.png

Et le programme affiche bien la trombine de l'homme le plus classe du monde :

godot_diapo_wayne.png godot_diapo_wayne.png

Si vous changez la variable à l'intérieur de set_texture(), par exemple en mettant s.set_texture( image4 ), le programme change également :

godot_diapo_d.png godot_diapo_d.png

godot_diapo_gable.png godot_diapo_gable.png

C'est grâce à ce principe que nous allons créer notre diaporama. Pour cela, nous n'allons pas directement nous servir des variables, mais les stocker dans une liste, comme ceci :

godot_diapo_e.png godot_diapo_e.png

Une liste permet de stocker une suite de variable, puis d'y accéder en utilisant un index.

Nous créons d'abord la liste :

var   liste_image   =   [   image1,   image2,   image3,   image4,   image5   ]

Et si nous utilisons ensuite le code :

liste_image[0]

Nous obtiendrons la première variable de la liste.

liste_image[1]

Pour la seconde. Et cætera. Attention ! L'index commence à 0, non pas à 1, de plus, une erreur se produira si vous essayez d'accéder à un index qui ne contient pas de données (par exemple, ici, liste_image[42]).

Revenons à nos moutons et essayons de modifier notre fonction set_texture() :

godot_diapo_f.png godot_diapo_f.png

godot_diapo_redford.png godot_diapo_redford.png

Haha, sacré Robert ! Bon, plus qu'une étape avant que vous ne compreniez l'intérêt de la méthode. Créez une nouvelle variable, image_n, égale à 0, et remplacez set_texture( image_list[2] ) par set_texture( image_list[image_n] ).

godot_diapo_g.png godot_diapo_g.png

Lancez la scène principale pour retrouver l'homme le plus classe du monde, bien vivant.

godot_diapo_wayne.png godot_diapo_wayne.png

Je pense que vous avez saisi : nous n'avons maintenant plus qu'à modifier image_n pour changer l'image du Sprite. En modifiant image_n, cela modifiera également l'index que nous allons chercher en tapant liste_image[image_n], ce qui modifiera donc l'image que nous attachons au Sprite en faisant set_texture( liste_image[image_n] ). Les deux boutons ne servirons donc qu'à augmenter ou diminuer image_n de 1.

Le système de contrôles de Godot, permettant de créer l'interface utilisateur, est extrêmement polyvalent. Pensé pour permettre d'exporter ses programmes sur différentes tailles d'écrans, il est au début assez complexe à appréhender. Le but ici est de survoler les grands principes sans rentrer dans les détails, ce qui nous noierait sous des montagnes d'explication.

Le plus simple est généralement de regrouper tous les contrôles dans une fenêtre dédiée à ceux-ci. Il existe un nœud pour ce faire : Panel. Commençons par en créer un dans la fonction _ready(): :

godot_diapo_h.png godot_diapo_h.png

Si nous lancions la scène maintenant, il n’apparaîtrait pas, car nous ne lui avons pas assigné de dimensions. Les contrôles sont tous des rectangles, qui se positionnent à l'aide de la fonction set_margin(). set_margin() prend deux arguments, c'est-à-dire qu'il y aura deux nombres entre parenthèses : le premier définit le bord du rectangle que nous souhaitons positionner, le deuxième sa position en pixel. Le premier nombre peut être 0 pour le bord gauche, 1 pour le bord haut, 2 pour le bord droit et 3 pour le bord gauche.

Dans notre cas, nous souhaiterions aligner les bord de ce panel sur les bords de l'image. Le bord gauche de l'image est situé à 100 pixels, son bord droit à 500 pixel. Nous allons donc redimensionner le panel comme ceci :

panel.set_margin(   0,   100   )

Pour mettre le bord gauche ( 0 ) à 100 pixels.

panel.set_margin(   2,   500   )

Pour mettre le bord droit ( 2 ) à 500 pixels.

Ensuite, nous souhaiterions faire commencer le haut du panel 10 pixels en-dessous de l'image, soit à 420 pixels, et le faire finir à 10 pixels du bas de la fenêtre du programme, soit à 590 pixels.

<code>panel.set_margin( 1, 420 )

panel.set_margin( 3, 590 )</code>

godot_diapo_i.png godot_diapo_i.png

Lorsque nous lançons le programme, celle-ci apparaît maintenant aux bonnes positions !

godot_diapo_j.png godot_diapo_j.png

Nous allons maintenant rajouter un premier bouton, bouton_gauche. Nous n'allons cependant pas l'ajouter à la scène. Nous allons l'ajouter à l'intérieur de panel :

godot_diapo_k.png godot_diapo_k.png

Lançons le programme sans avoir précisé la position du bouton.

godot_diapo_l.png godot_diapo_l.png

Celui-ci n'apparaît pas en haut à gauche de la fenêtre, mais en haut à gauche de panel ! En effet, rajouter un contrôle à l'intérieur d'un autre contrôle rend sa position relative au contrôle auquel il a été ajouté. Plus précisément, elle la rend relative au coin haut/gauche du contrôle parent.

Premièrement, pour des raisons esthétiques, nous allons situer le bouton à 10 pixels du bord de panel, en le modifiant avec set_margin() :

<code>bouton_gauche.set_margin( 0, 10 )

bouton_gauche.set_margin( 1, 10 )</code>

godot_diapo_m.png godot_diapo_m.png

godot_diapo_n.png godot_diapo_n.png

Le bord gauche du bouton est maintenant situé à 10 pixels du bord gauche du panel, et son bord haut à 10 pixel du bord haut du panel. Bien. Maintenant, élargissons le :

bouton_gauche.set_margin(   2,   195   )

godot_diapo_o.png godot_diapo_o.png

Le bord droit du bouton est maintenant situé à 195 pixel du bord gauche du panel.

godot_diapo_p.png godot_diapo_p.png

Nous pourrions faire la même chose pour son bord bas mais il existe une meilleure méthode. Par défaut, les bords bas et haut d'un contrôle sont situés relativement au bord haut de leur contrôle parent. Mais la fonction set_anchor() permet de changer ce réglage :

bouton_gauche.set_anchor(   3,   1   )

Le bord bas du bouton ( 3 ) est maintenant situé relativement au bord bas du panel, selon la règle 1 de set_anchor().

bouton_gauche.set_margin(   3,   10   )

Nous mettons maintenant le bord bas du bouton ( 3 ) à 10 pixels de décalage.

godot_diapo_q.png godot_diapo_q.png

En lançant la scène principale, on remarque que le bouton est maintenant aux bonnes dimensions ! Quel est l'intérêt de cette méthode ? Eh bien si nous changions maintenant la taille du panel, cela redimensionnerai également le bouton, puisque la taille du bouton est définie en fonction de la taille du panel !

godot_diapo_r.png godot_diapo_r.png

Maintenant que nous avons notre bouton, il est l'heure de le connecter. Comment cela fonctionne-t-il ? Les contrôles, lorsqu'ils reçoivent une commande, émettent un signal. Dans le cas d'un bouton, il émettra le signal “button_down” lorsque l'on cliquera dessus. La ligne de commande suivante va permettre de connecter le signal “button_down” à une fonction que nous appellerons “photo_precedente” :

godot_diapo_s.png godot_diapo_s.png

Cela signifie que lorsque bouton_gauche émettra le signal “button_down”, le nœud self (qui fait référence ici à main.tscn) exécutera la fonction photo_precedente() . Que nous allons maintenant créer :

godot_diapo_t.png godot_diapo_t.png

Comme nous l'avions dit, le but de ce bouton est de baisser image_n de 1. Il y a cependant un risque. Si image_n est à 0, elle passera à -1. Or, il n'existe pas d'index -1 dans liste_image, ce qui risque de générer une erreur. Dans le cas où image_n serait égale à 0, nous aimerions qu'elle repasse à l'index maximum de liste_image. Il existe une fonction qui permet de récupérer l'index maximum d'une list : .size() . liste_image.size() donnera un nombre égal au nombre de variable dans image_list, en partant de 1. Comme l'index part de 0, il faudra donc, si image_n est égale à 0 et que nous cliquons sur le bouton pour aller à l'image précédente, que image_n devienne égale à liste_image.size() - 1 . Dans le cas contraire, il faut baisser image_n de 1 :

godot_diapo_u.png godot_diapo_u.png

Enfin, comme l'image a changée, il faut mettre à jour le Sprite :

godot_diapo_v.png godot_diapo_v.png

Lancez le programme et appuyez sur le bouton : vous pouvez maintenant, dans un sens, naviguer entre les images !

Maintenant, nous allons nous occuper du deuxième bouton. Copiez-collez le premier bouton et changez le nom de la variable par bouton_droite:

godot_diapo_w.png godot_diapo_w.png

Les bords haut et bas sont aux bonnes positions, mais les bords gauche et droit sont aux mêmes endroits que ceux du côté gauche. Pourtant, il n'est quasiment pas nécessaire de toucher aux dimensions du bouton. Plutôt que de positionner ses côtés par rapport au côté gauche du panel, nous allons les positionner par rapport au côté droit du panel :

<code>bouton_droit.set_anchor( 0, 1 )

bouton_droit.set_anchor( 2, 1 )</code>

Puis intervertir les valeurs de set_margin( 0, a ) et set_margin( 2, b ) :

godot_diapo_x.png godot_diapo_x.png

Quand nous lançons le programme, les deux boutons sont correctement placés.

godot_diapo_y.png godot_diapo_y.png

Maintenant, il s'agit de changer la connexion du bouton droit pour la fonction “photo_suivante”.

godot_diapo_z.png godot_diapo_z.png

Ensuite, copier-coller photo_precedente(), changer son nom par photo_suivante(), et inverser sa logique : si image_n est égale à liste_image.size() - 1, alors image_n = 0. Sinon, on augmente image_n de 1. Puis on met à jour l'image !

godot_diapo_aa.png godot_diapo_aa.png

Voilà, vous pouvez maintenant lancer le programme et admirer le trombinoscope de vos rêves !

Vous savez maintenant utiliser une liste et accéder aux éléments qui la composent. Même si ça n'a l'air de rien de prime abord, c'est un outil très puissant pour ranger les variables par catégories. Mieux encore, une liste peut elle-même contenir d'autres listes afin d'obtenir un système de classement complexe.

Nous avons aussi effleuré le concept de contrôle bien qu'il nécessite un peu de pratique pour être totalement appréhendé. Je vous conseille de faire un tour dans la documentation pour regarder les différents types de contrôles et les signaux qu'ils émettent, afin d'avoir une meilleure vision des programmes que vous pourriez mettre en place.

Sur ce, j'me taperai bien une 'ouiche.

main.gd

extends Node2D
 
var image1 = preload("res://data/trombines/wayne.png")
var image2 = preload("res://data/trombines/newman.png")
var image3 = preload("res://data/trombines/redford.png")
var image4 = preload("res://data/trombines/gable.png")
var image5 = preload("res://data/trombines/fonda.png")
 
var liste_image = [ image1, image2, image3, image4, image5 ]
 
var image_n = 0
 
var s
 
func _ready():
    s = Sprite.new()
    s.set_pos( Vector2( 300, 210 ) )
    s.set_texture( liste_image[image_n] )
    add_child( s )
 
    var panel = Panel.new()
    panel.set_margin( 0, 100 )
    panel.set_margin( 2, 500 )
 
    panel.set_margin( 1, 420 )
    panel.set_margin( 3, 590 )
    add_child(panel)
 
    var bouton_gauche = Button.new()
    bouton_gauche.set_margin( 0, 10 )
    bouton_gauche.set_margin( 1, 10 )
    bouton_gauche.set_margin( 2, 195 )
 
    bouton_gauche.set_anchor( 3, 1 )
    bouton_gauche.set_margin( 3, 10 )
 
    bouton_gauche.connect("button_down", self, "photo_precedente")
    panel.add_child( bouton_gauche )
 
    var bouton_droit = Button.new()
 
    bouton_droit.set_anchor( 0, 1 )
    bouton_droit.set_anchor( 2, 1 )
 
    bouton_droit.set_margin( 0, 195 )
    bouton_droit.set_margin( 1, 10 )
    bouton_droit.set_margin( 2, 10 )
 
    bouton_droit.set_anchor( 3, 1 )
    bouton_droit.set_margin( 3, 10 )
 
    bouton_droit.connect("button_down", self, "photo_suivante")
    panel.add_child( bouton_droit )
 
func photo_precedente():
    if image_n = 0:
        image_n = liste_image.size()-1
    else:
        image_n -= 1
    s.set_texture( liste_image[image_n] )
 
func photo_suivante():
    if image_n = liste_image.size()-1:
        image_n = 0
    else:
        image_n += 1
    s.set_texture( liste_image[image_n] )
  • godot_listes_et_boutons.txt
  • Dernière modification: 2018/10/24 14:28
  • par serge