Choisir le bon pop-up
Un pop-up interrompt. Avant d'en choisir un, répondez à une seule question : le joueur doit-il répondre avant que le jeu continue ? Si oui, bloquez. Si non, ne bloquez jamais — une carte qui arrête le jeu pour une nouvelle que le joueur n'a pas demandée est le moyen le plus rapide de lui faire fermer votre jeu.
- Une question qui attend une réponse — acheter, supprimer, quitter, écraser →
GoDialogs.confirm(). Une information à prendre en compte →alert(). Une option parmi quelques-unes →choose(). - Un écran à part entière — les réglages, une fiche de personnage, un article de boutique →
GoSurfaceau milieu de l'écran. - Une longue liste ou une page de gestion — la besace, le courrier, les amis →
GoSheetdepuis le bas sur un téléphone,GoDrawerdepuis le côté sur un grand écran. - Quelque chose sur ce qu'on vient d'appuyer — les statistiques d'un objet, ses actions →
GoPopoverouGoContextMenujuste à côté. - Une nouvelle pendant laquelle le jeu peut continuer — sauvegardé, lâché, invité →
GoSnackbar,GoNoticeouGoPromptCard. Ceux-là ne prennent jamais l'écran. - Apprendre les commandes →
GoCoachMark. Des triches pendant le développement →GoConsole.
Tous les pop-ups d'un coup d'œil
| Pop-up | Arrête le jeu | Retour / Échap | Un appui à l'extérieur | Sert à |
|---|---|---|---|---|
GoDialogs confirm · alert | Oui | La ferme — confirm répond false, alert rend la main | La ferme seulement avec dismiss_on_scrim | Les questions qui demandent une réponse |
GoDialogs.choose | Oui | La ferme — répond -1 | La ferme seulement avec dismiss_on_scrim | Choisir parmi quelques options |
GoSurface | Oui | Demande la fermeture de la fenêtre du dessus | Demande la fermeture avec dismiss_on_scrim | Vos propres fenêtres |
GoSheet | Oui | Ferme toute la feuille | La ferme | La besace, une liste de boutique, le courrier |
GoDrawer | Oui | Retour Android seulement | Le ferme | Une liste latérale sur un grand écran |
GoPopover | Jusqu'à sa fermeture | La ferme | La ferme — et ne va pas plus loin | Le détail des objets et des compétences |
GoCombobox liste | Jusqu'à sa fermeture | La ferme | La ferme | Une liste de choix avec recherche |
GoContextMenu · dropdown · select | Le menu du moteur | Le menu du moteur | Le ferme | Des actions, des listes courtes |
GoSnackbar | Non | — | Atteint le jeu | Sauvegardé · Annuler · Réessayer |
GoPromptCard | Non | — | Atteint le jeu | Une invitation, une demande d'échange |
GoNotice | Jamais | — | Atteint le jeu | Une ligne fixe sur le HUD |
GoBanner | Non — il fait partie de la page | — | — | « Vous êtes hors ligne. Réessayer » |
GoCoachMark | Sa carte seulement | Termine la visite | Atteint le jeu | Une visite au premier lancement |
GoConsole | Son panneau seulement | La touche Échap la ferme | Atteint le jeu | Des commandes de débogage |
Le calque sur lequel chacun s'ouvre, et pourquoi dans cet ordre, est expliqué dans Calques, Retour et saisie.

GoDialogs
GoSurface
GoSheet
GoDrawer
GoPopover
GoContextMenu
GoSnackbar
GoPromptCard
GoCoachMark
GoConsoleChaque image de cette page montre le même petit jeu — vie et mana en haut à gauche, pièces en haut à droite, un joystick et
trois emplacements rapides en bas — en default_dark, avec un pop-up ouvert par-dessus. Le même
pop-up dans les quatorze apparences →
Anatomie d'un pop-up
Presque tous les pop-ups bloquants de gohud — boîtes de dialogue, feuilles, cartes épinglées, la liste du combobox et
vos propres fenêtres — reposent sur un seul nœud, GoSurface. Apprenez ses parties une fois et vous les connaissez toutes.

| Partie | Ce que c'est | Comment y accéder |
|---|---|---|
| Calque | Le CanvasLayer sur lequel vit le pop-up. Son numéro décide de ce qu'il recouvre. | À vous pour un GoSurface ; intégré pour les autres (tableau) |
| Voile | Le voile posé sur tout ce qui se trouve derrière. Il attrape les appuis qui manquent la carte. | scrim_transparent, dismiss_on_scrim, la couleur scrim du thème |
| Carte | La fenêtre elle-même — la face de panneau du thème, arrondie, coupée, forgée ou en gelée selon l'apparence. | card, alpha |
| En-tête | Un bouton retour facultatif, le titre (deux lignes au plus, puis « … »), le bouton de fermeture. | set_title() · set_title_key() · set_back() · close_enabled · show_header |
| Barre d'outils | Une rangée fixe sous l'en-tête — un champ de recherche, des puces de filtre. Masquée tant que vous ne l'utilisez pas. | toolbar |
| Corps | La partie qui défile. Mettez-y le contenu. | body · scroll_body · clear() |
| Ligne d'état | Une ligne fixe entre le corps et le pied — « Échec de la vérification du nom », « Enregistrement… ». | set_status_text() · set_status_key() · clear_status() |
| Pied | Des boutons fixes en bas. Masqué tant que vous ne l'utilisez pas. | footer |
toolbar, la ligne d'état et footer ; ils restent en place pendant que le corps défile.
Des boîtes de dialogue que vous await
GoDialogs pose la question et attend. Un nœud, trois questions — et la réponse revient sur la même
ligne, si bien que le code se lit dans l'ordre où le joueur le vit.
var dialogs := GoDialogs.new()
add_child(dialogs)
if await dialogs.confirm("Buy the starter pack?", "300 gems for a sword, a shield and 10 potions.",
"Buy", "Not now"):
buy_starter_pack()

confirm()
confirm(…, true) — destructive
alert()
choose()
ActionLayout.HORIZONTALLes trois questions
confirm(title, body, ok_text := "", cancel_text := "", extra := "",
args := {}, destructive := false) -> bool
alert(title, body, ok_text := "", extra := "", args := {}) # await pour attendre
choose(title, options: Array, cancel_text := "", translate := false) -> int
confirm_key(…) · alert_key(…) # clés de traduction
| Appel | Renvoie | Sert à |
|---|---|---|
confirm() | true ou false | Oui ou non — acheter, supprimer, quitter, écraser. |
alert() | rien — faites await dessus pour attendre | Ce que le joueur doit voir : une récompense, une connexion perdue. |
choose() | l'indice de l'option, ou -1 | Une option parmi quelques-unes. Une option est un String ou {text, icon, danger, subtitle}. |
confirm_key() · alert_key() | comme ci-dessus | La même chose avec des clés de traduction — les mots suivent un changement de langue pendant que la boîte de dialogue est ouverte. |
Des libellés de bouton vides retombent sur les mots du kit (confirm, cancel dans GoConfig.text_keys).
extra s'ajoute au corps sur une nouvelle ligne. args remplit les {placeholders} du titre
et du corps : confirm("Buy {item}?", "It costs {price} gold.", "Buy", "", "", {"item": name, "price": 300}).
Chaque sortie a sa réponse
| Le joueur… | confirm | alert | choose |
|---|---|---|---|
| appuie sur OK / une option | true | rend la main | l'indice de l'option |
| appuie sur Annuler | false | — | -1 |
| appuie sur ×, Échap ou Retour Android | false | rend la main | -1 |
appuie sur le voile (seulement avec dismiss_on_scrim) | false | rend la main | -1 |
le nœud GoDialogs quitte l'arbre | false | rend la main | -1 |
Le code qui suit await s'exécute donc toujours — aucune réponse ne reste en suspens, même quand la scène change sous la boîte de dialogue.
Actions destructives
Passez destructive = true pour ce qui ne peut pas être annulé. Le bouton OK devient le bouton plein
Tone.DANGER_SOLID — blanc sur rouge dans chaque apparence, là où un libellé de danger teinté devrait s'assombrir
presque jusqu'au noir sur un thème clair pour rester lisible. La tonalité est réinitialisée à chaque appel, car la fenêtre est réutilisée.
if await dialogs.confirm("Delete this save?", "Slot 2 — Aria, level 12. This cannot be undone.",
"Delete", "Keep it", "", {}, true):
delete_save(2)
Disposition des boutons
action_layout | Ce qu'il fait |
|---|---|
VERTICAL (par défaut) | Boutons empilés, pleine largeur. Sûr dans toutes les langues — un long libellé allemand ou russe n'est jamais comprimé. |
HORIZONTAL | Une seule rangée, la moitié de la largeur chacun. |
AUTO | Une seule rangée quand les deux libellés tiennent sur une ligne dans la moitié de la carte ; empilés sinon. Décidé de nouveau à chaque changement de langue ou de taille. |
action_gap est l'espace entre les boutons, body_gap l'espace au-dessus d'eux — faites-le plus large que
l'écart entre boutons pour que la question et le choix se lisent comme deux parties. Pour une seule boîte de dialogue, appelez
set_next_action_layout() avant de l'ouvrir. Le bouton unique d'une alerte prend toujours toute la largeur.
Une à la fois
Un second confirm() pendant qu'une boîte de dialogue est ouverte renvoie false immédiatement — une boîte
de dialogue ne s'empile jamais par accident sur une autre. Activez queue_when_busy et elle attend son tour à la place ;
alert() attend toujours. queue_limit (8) plafonne la file, et en cas de débordement la demande la plus
ancienne reçoit false. pending() compte les demandes en attente et clear_pending() leur répond
à toutes false. choose() ne se met jamais en file : il renvoie -1 quand une boîte de dialogue est déjà ouverte.
Téléphone et ordinateur
choose() s'ouvre en feuille depuis le bas sur Android et iOS — là où se trouve le pouce — et en carte au milieu
sur un ordinateur. Une confirmation est plafonnée à max_width (420dp) et centrée. Réglez layer_index,
max_width et les autres exports avant add_child ; ils sont appliqués quand le nœud entre dans l'arbre.
var picked := await dialogs.choose("Sort the bag by", [
{"text": "Newest first", "icon": GoIconSet.CLOCK},
{"text": "Rarity", "icon": GoIconSet.STAR},
{"text": "Drop everything", "icon": GoIconSet.TRASH, "danger": true}])
if picked >= 0:
sort_bag(picked)
GoSurface — une fenêtre à vous
Quand un pop-up est plus qu'une question — des réglages, une fiche de personnage, un objet à acheter —, construisez-le
sur GoSurface. La zone sûre, le clavier, les rangées fixes, le défilement, Retour, le focus et le redimensionnement sont déjà réglés.
var layer := CanvasLayer.new()
layer.layer = 50
add_child(layer)
var window := GoSurface.new()
window.set_title("Settings")
window.close_requested.connect(layer.queue_free)
window.body.add_child(GoStyle.toggle("Music", false))
window.body.add_child(GoStyle.slider(0.0, 1.0, 0.05))
var row := GoStyle.row()
row.add_child(GoStyle.button("Cancel", window.request_close))
row.add_child(GoStyle.button("Save", save_and_close, GoStyle.Tone.PRIMARY))
window.footer.add_child(row)
window.footer.visible = true
layer.add_child(window)
close_requested.
Masquer ou libérer la fenêtre revient à l'écran propriétaire — lui seul sait si « fermer » veut dire enregistrer, abandonner ou demander d'abord.
Trois placements

CENTER — confirmations, réglages
BOTTOM — listes, pages de gestion
ANCHOR — à côté d'une commande
GoDatePicker dans une fenêtre CENTERANCHOR a besoin de anchor_control. La carte se place à sa droite si anchor_min_width y tient,
sinon du côté le plus large, sinon à l'intérieur de l'écran, et s'ouvre vers le haut quand il y a plus de place au-dessus. Elle suit
une ancre mobile à chaque image. anchor_width (320) et anchor_max_height (520) la dimensionnent.
Quelle taille elle prend
| Mesure | Règle | Se change avec |
|---|---|---|
| Espace | La zone sûre, moins le clavier, moins la marge d'écran (16dp, jamais plus de 10 % du petit côté). | — |
| Largeur | 94 % de l'espace en portrait, 72 % en paysage, 480dp au plus. | max_width · GoConfig.surface_width_ratio_* |
| Hauteur | Aussi haute que le contenu (fit_content), jusqu'à 68 % de l'espace, plafonnée à 72 %. Une carte centrée non redimensionnable peut monter jusqu'à 94 % pour éviter le défilement. | height_ratio · max_height_ratio · max_height |
| Densité | Dense quand compact est activé, quand l'écran fait moins de 420dp de haut (un téléphone couché) ou quand le contenu ne tient pas : moins de marge intérieure, des écarts plus petits, un titre plus petit. Elle mesure les deux et garde la plus aérée qui tient — sans tremblement. | compact |
| Redimensionnement | Avec resizable, le titre sert de poignée : faites-le glisser entre 30 % et le plafond. height_changed(ratio) rapporte le résultat. | resizable |
Un ratio au-dessus du plafond est ramené au plafond, avec un seul avertissement dans une version de débogage. Le clavier pousse la carte vers le haut et fait défiler le champ qui a le focus jusqu'à le rendre visible ; la zone sûre la tient à l'écart de l'encoche et de la barre de gestes sur Android et iOS.
Propriétés
| Propriété | Par défaut | Ce qu'elle fait |
|---|---|---|
placement | CENTER | CENTER, BOTTOM ou ANCHOR |
dismiss_on_scrim | GoConfig.dismiss_on_scrim (false) | Un appui sur le voile demande la fermeture. Un glissement commencé dans la carte, non. |
scrim_transparent | false | Garder le jeu visible — le voile attrape toujours les appuis extérieurs. |
close_enabled | true | Afficher × et laisser Échap et Retour demander la fermeture. |
show_header · scroll_body · resizable | true · true · false | La rangée d'en-tête, le corps défilant, la poignée de glissement. |
fit_content · compact | true · false | S'ajuster au contenu ; démarrer en mode dense. |
fade_in | GoConfig.surface_fade_in (false) | Faire apparaître la carte en fondu à l'ouverture. Instantané sous reduce_motion. |
alpha | -1 (celle du thème) | L'opacité de la face de la carte, en ratio. Seule la face s'estompe — jamais le texte. |
initial_focus | aucun | La commande qui reçoit le focus à l'ouverture. |
add_child : scrim_transparent, show_header, resizable et
scroll_body sont appliquées quand la fenêtre entre dans l'arbre. dismiss_on_scrim, close_enabled,
fade_in et initial_focus sont lues en direct.
Signaux et appels
| Nom | Ce que c'est |
|---|---|
close_requested | ×, Échap, Retour Android ou un appui sur le voile — et request_close(). Émis seulement par la fenêtre du dessus. |
back_requested · set_back(action) | Le bouton retour de l'en-tête, pour une fenêtre à plusieurs pages. Un Callable vide le masque. |
height_changed(ratio) | Après un glissement de la poignée. |
is_top() · GoSurface.is_any_open() | Est-ce la fenêtre qui reçoit Retour — une fenêtre, quelle qu'elle soit, est-elle ouverte. |
relayout() | Refaire la mise en page maintenant. Changer une propriété de dimensionnement le fait déjà pour vous. |
Feuilles et tiroirs
Une liste qui a besoin de place monte depuis le bas sur un téléphone tenu à la verticale — là où se trouve le pouce — et arrive par le côté sur une tablette ou un ordinateur, où une feuille recouvrirait le jeu.

GoSheet
GoDrawer · LEFT
GoDrawer · RIGHTGoSheet — des pages venues du bas
var sheet := GoSheet.new()
add_child(sheet)
func show_bag(items: Array) -> void:
sheet.open("Bag")
var search := GoStyle.line_edit("Search the bag…")
search.text_changed.connect(filter_bag)
sheet.toolbar().add_child(search)
sheet.toolbar().visible = true
for item in items:
sheet.body.add_child(GoStyle.list_button(GoIconSet.BOX, item.name, show_item.bind(item),
Color.TRANSPARENT, item.description, false, GoIconSet.CHEVRON_RIGHT))
sheet.add_footer(GoStyle.button("Close", sheet.close, GoStyle.Tone.PRIMARY))
- C'est un
CanvasLayer(calque 10) qui contient unGoSurfaceBOTTOMredimensionnable — il se place donc au-dessus du HUD, et le joueur peut l'agrandir en le faisant glisser. open(title)commence une nouvelle page : il vide le corps, la barre d'outils et le bouton retour, et libère ce queadd_footer()a ajouté. Rappelez-le pour afficher une autre page dans la même feuille ;set_back()affiche un bouton retour pour revenir à la page d'accueil.open_key()prend une clé de traduction.close()la masque — elle n'est pas libérée, si bien que leopen()suivant est instantané.closedetpage_changedvous préviennent.height_ratio(0.6) est la hauteur d'ouverture ;max_height_ratiorelève le plafond ;dismissable(true) la ferme sur un appui sur le voile.
set_back() — seul le bouton retour à l'écran
revient d'une page. Si Retour doit revenir d'une page, gérez vous-même close_requested sur sheet.surface.
GoDrawer — depuis le côté
var drawer := GoDrawer.new()
drawer.side = GoDrawer.Side.LEFT
drawer.follow_text_direction = true # le côté du début : la gauche, ou la droite en arabe
add_child(drawer)
drawer.body.add_child(GoNavBar.drawer_list([{"icon": GoIconSet.HOME, "text": "Town"},
{"icon": GoIconSet.MAP, "text": "World map"}], 0, go_to))
drawer.open("Menu")
- Calque 80. 42 % de la largeur de l'écran (
width_ratio), entremin_width(320dp) etmax_width(420dp) — sur un téléphone, il couvre la plus grande partie de l'écran, c'est pourquoi une feuille y est le meilleur choix. - Le panneau va jusqu'au bord de l'écran ; seul son contenu se retire de la zone sûre, pour qu'un coin arrondi ne rogne jamais la première rangée.
LEFTveut dire la gauche de l'écran, même en arabe. Activezfollow_text_directionquand c'est « le côté du début » qui compte ;effective_side()vous dit de quel côté il s'est placé.open(title)garde le corps — remplissez-le une fois.set_title("")masque l'en-tête.motion_seconds(0.2) le fait glisser ;reduce_motionle rend instantané.
drawer.close() depuis votre propre raccourci clavier — et notez que GoSurface.is_any_open() ne compte pas les tiroirs ;
demandez à drawer.is_open().
Cartes et menus à côté d'une commande
Ce sur quoi le joueur vient d'appuyer mérite une réponse juste à côté du doigt, pas au milieu de l'écran.

GoPopover
GoContextMenu
GoStyle.dropdown()
GoStyle.select()
GoComboboxGoPopover — une carte sur ce qu'on a appuyé
slot.pressed.connect(func() -> void:
var card := GoStyle.item_card({"icon": GoIconSet.POTION, "title": "Health potion",
"subtitle": "Heals 50 HP · 12 left"}, false)
GoPopover.open(slot, card, {"width": 280}))
Une surface ANCHOR dont le calque, l'ancre et la libération sont déjà câblés — les dix lignes que chaque jeu réécrit
encore et encore. Une seule à la fois : en ouvrir une seconde ferme la première, parce que des cartes empilées enterrent l'écran
et plus personne ne sait laquelle appartient à quel emplacement. Le voile est transparent — une carte ouverte pour comparer un équipement
ne doit pas assombrir cet équipement — mais il attrape quand même le premier appui extérieur, qui ferme la carte et ne va pas plus loin.
| Option | Par défaut | Ce qu'elle fait |
|---|---|---|
title | "" | Un en-tête avec ×. Vide : pas d'en-tête. |
width · max_height | 320 · 520 | La taille de la carte. |
dismissable | true | Un appui extérieur la ferme. |
compact · alpha · translate | false · -1 · false | Espacement dense, opacité de la face, titre comme clé de traduction. |
layer | 95 | Le CanvasLayer sur lequel elle s'ouvre. |
GoPopover.close() et GoPopover.is_open() sont statiques. open() renvoie la surface — ou
null quand l'ancre n'est pas dans l'arbre : vérifiez avant de faire await shown.close_requested.
dismissable = false et sans titre, rien à l'écran ne la ferme — seulement Échap, Retour ou votre propre appel.
GoContextMenu — appui long et clic droit
var menu := [
{"text": "Use", "icon": GoIconSet.POTION, "action": use},
{"separator": true},
{"text": "Drop", "icon": GoIconSet.TRASH, "action": drop, "danger": true}]
GoContextMenu.attach(slot, menu)
var more := GoStyle.icon_button(GoIconSet.MORE, Callable(), -1, &"more")
more.pressed.connect(func() -> void: GoContextMenu.open_at(more, menu))
- Un clic droit l'ouvre aussitôt. Un doigt maintenu une demi-seconde (
HOLD_SECONDS) l'ouvre ; bouger de plus de 12dp annule — faire défiler une liste ne fait donc jamais surgir de menu. - Une entrée est
{text, action, icon, disabled, checked, separator, danger, translate}. Passez unCallableau lieu du tableau quand les entrées dépendent de ce sur quoi on a appuyé ; il est appelé à chaque ouverture du menu. dangerplace « ⚠ » devant le texte — le menu du moteur ne sait colorer que toutes ses entrées à la fois.- C'est le
PopupMenudu moteur, habillé parGoStyle.style_popup(). Il ne compte pas comme une surface ouverte.
⋯ visible
(open_at(), comme ci-dessus), ou enseignez-le une fois avec un repère guidé.
Listes déroulantes, sélecteurs et bouton divisé
var sort := GoStyle.dropdown("Sort", ["Highest score", "Most wins", {"text": "Friends only", "disabled": true}],
func(index: int) -> void: sort_board(index))
var quality := GoStyle.select(["Low", "Medium", "High", "Ultra"], "Quality")
quality.item_selected.connect(func(index: int) -> void: settings.quality = index)
var send := GoSplitButton.make("Send", send_now, ["Send later", "Save as draft"])
Les trois ouvrent le menu contextuel du moteur : dropdown() est un MenuButton qui lance une action,
select() un OptionButton qui garde une valeur, GoSplitButton une action principale avec un menu sur
sa flèche (chosen(index)). Les menus restent entièrement opaques exprès — un menu affiché dans sa propre fenêtre du système
rend noirs les pixels translucides.
GoCombobox — une liste avec recherche
var friend := GoCombobox.make(friend_names, -1, "Find a friend")
friend.picked.connect(func(index: int) -> void: invite(friend_names[index]))
Une fois pressé, il ouvre une liste ancrée sur le calque 96 avec un voile transparent. À partir de search_threshold (8) entrées,
un champ de recherche apparaît et prend le focus ; il trouve une correspondance n'importe où dans le texte ou l'indication, sans tenir compte
de la casse, et un résultat vide le signale. list_width (0 = la largeur du bouton, au moins 180dp) dimensionne la liste.
Des pop-ups qui n'arrêtent jamais le jeu
Des nouvelles que le joueur peut lire en jouant. Aucun n'a de voile ; un appui n'importe où ailleurs que sur la carte elle-même va au jeu.

GoSnackbar
GoNotice
GoPromptCard
GoStyle.tooltip_node()GoSnackbar — un message avec Annuler
var snack := GoSnackbar.new()
add_child(snack)
if await snack.post({"text": "Dropped {name}", "args": {"name": item.name}, "icon": GoIconSet.TRASH,
"actions": ["Undo"], "seconds": 5.0}) == 0:
restore(item)
Clé de post() | Ce qu'elle fait |
|---|---|
text · title · args · translate | Le message, une ligne en gras facultative, des {placeholders}, des clés de traduction. |
tone · icon | La couleur d'accent (GoTheme.SUCCESS, WARNING…) et une icône. |
actions · closable | Des boutons — des String ou {text, action} — et un ×. |
seconds | Combien de temps il reste affiché. Négatif : le notice_duration_ms du thème. 0 : jusqu'à ce qu'on le ferme — donnez-lui alors un bouton. |
post() renvoie l'indice du bouton pressé, ou -1 quand le délai a expiré ou que le message a été fermé. Les messages
se mettent en file (queue_limit 4, le plus ancien abandonné avec -1), et le même texte publié de nouveau pendant qu'il s'affiche
ne fait que relancer son minuteur. Il se place en bas (ou en haut, placement), au-dessus de la zone sûre et du clavier, sur le
calque 90 — lisible par-dessus un tiroir. Avec tap_to_dismiss (activé), un appui sur une carte sans boutons la ferme ; un appui
hors de la carte atteint toujours le jeu. show_text() et show_key() sont les formes en une ligne.
GoNotice — une ligne sur le HUD
var notice := GoNotice.new()
hud_corner.add_child(notice)
notice.show_text("Game saved", GoTheme.SUCCESS)
notice.custom_minimum_size.x = notice.preferred_width(340)
Un simple panneau que vous placez vous-même — dans un GoHudAnchor, dans un coin, n'importe où. Il ne prend ni la saisie ni le focus :
appuyer à travers lui atteint le bouton en dessous, et un nouveau message remplace l'ancien. Donnez-lui une largeur :
preferred_width(limit) renvoie la largeur naturelle d'un texte court et fait passer à la ligne un texte long dans limit.
set_content() affiche n'importe quelle commande à la place du texte.
GoPromptCard — une question qui peut attendre
var spot := GoHudAnchor.new()
spot.spot = GoHudAnchor.Spot.TOP_CENTER
spot.reserve_space = false
spot.avoid_peers = true # se placer sous les barres de vie au lieu de les couvrir
hud.add_child(spot)
var invite := GoPromptCard.new()
spot.add_child(invite)
invite.set_icon(GoIconSet.USERS, Color.TRANSPARENT, true)
invite.set_title("Party invite from Ann")
invite.set_subtitle("Dragon's Lair · 3 / 4 members")
invite.set_actions([{"text": "Accept", "action": accept, "primary": true},
{"text": "Decline", "action": invite.hide}])
invite.fit_width(340)
invite.show()
get_tree().create_timer(15.0).timeout.connect(invite.hide)
- Elle démarre masquée — appelez
show(). Elle n'a pas de minuteur propre ; ajoutez-en un si la question expire. - Ses boutons ne la ferment pas — ce sont les actions qui décident. × (
set_closable(true)) émetclosed. fit_width(width)fixe la largeur et prédit la hauteur d'après la police, pour que rien de ce qui est disposé par rapport à elle ne saute une image plus tard.- Sa face suit
hud_alpha— elle fait partie du HUD, ce n'est pas une fenêtre.
GoBanner et infobulles
GoBanner.make("You're offline.", [{"text": "Retry", "action": reconnect}], GoIconSet.WARNING) se place dans la page
elle-même, au-dessus du contenu, et n'expire jamais ; un bouton le ferme, sauf s'il a "keep": true.
GoStyle.tooltip_node(text) est ce qu'il faut renvoyer depuis _make_custom_tooltip() — le moteur dessine le fond
(TooltipPanel), gohud le texte, avec retour à la ligne au-delà de 260dp. Les infobulles sont faites pour la souris ; ne cachez jamais derrière elles ce dont un joueur a besoin.
Visites guidées et console

GoCoachMark
GoConsoleGoCoachMark — une visite des vraies commandes
var tour := GoCoachMark.new()
tour.keep_clear = [top_bar]
tour_layer.add_child(tour)
tour.finished.connect(func(completed: bool) -> void: save.tutorial_done = true)
tour.start([{"target": bag_button, "title": "Bag", "body": "Everything you pick up lands here."},
{"target": map_button, "title": "Map", "body": "Tap to open the full map."}])
- Un anneau autour de la vraie commande et une carte à côté. Appuyer sur la cible fait avancer (son signal
pressed, ou"signal"dans l'étape) ; Suivant et Passer sont sur la carte. Une cible masquée est sautée. - La carte reste hors du milieu de l'écran (
avoid_center_band), à l'écart des ancres du HUD et dekeep_clear. - Tant qu'un
GoSurfaceest ouvert, la visite se masque et attend. Retour ou Échap la termine avecfinished(false). - Elle n'a pas de calque à elle — ajoutez-la en dernier, ou sur un calque au-dessus du HUD.
GoConsole — des triches pendant le développement
var console := GoConsole.new()
add_child(console)
console.register("give", "give <item> <count>", func(args: PackedStringArray) -> String:
return "gave %s x%s" % [args[0], args[1]] if args.size() >= 2 else "give <item> <count>")
func _unhandled_input(event: InputEvent) -> void:
if event.is_action_pressed(&"dev_console"): console.toggle()
Calque 200 — au-dessus de tout, pour pouvoir déboguer par-dessus une boîte de dialogue — et elle continue de tourner quand l'arbre est en pause. Une palette suggère des commandes à mesure que vous tapez ; Haut et Bas parcourent l'historique ; Échap la ferme. Il n'y a pas de touche intégrée : associez la vôtre.
debug_only (activé) la bloque dans une version de production — open() comme run(). Des commandes
de triche entre les mains d'un joueur achèvent l'économie d'un jeu dès le premier jour.
Calques, Retour et saisie
Trois règles décident de ce que le joueur peut toucher pendant que quelque chose est ouvert : ce qui est au-dessus, à qui appartient Retour, et qui reçoit un appui.
Ce qui est au-dessus
| Calque | Ce qui s'y trouve | Se règle avec |
|---|---|---|
| 5 | Votre HUD (à vous de choisir) | — |
| 10 | GoSheet | CanvasLayer.layer |
| ~50 | Vos propres fenêtres GoSurface, un menu de pause | votre CanvasLayer |
| 80 | GoDrawer | CanvasLayer.layer |
| 90 | GoSnackbar | layer_index |
| 95 | GoPopover | option "layer" |
| 96 | liste de GoCombobox | — |
| 100 | GoDialogs | layer_index |
| 200 | GoConsole | layer_index |
L'ordre est voulu : un snackbar rapporte ce qui vient de se passer, il se lit donc par-dessus un tiroir ; une carte épinglée appartient à ce qui vient d'être pressé, elle se place donc au-dessus ; une boîte de dialogue pose une question et couvre les deux ; la console couvre tout, parce que c'est ce que vous ouvrez quand tout le reste a mal tourné.
À qui appartient Retour
- Seule la fenêtre du dessus répond. Parmi les surfaces ouvertes, celle du calque le plus haut (puis la dernière dans l'arbre)
reçoit Échap, l'annulation de la manette (
ui_cancel), le Retour Android et les appuis sur le voile. Des fenêtres empilées se ferment une à la fois, jamais ensemble. - Le Retour Android est traité une image plus tard, si bien qu'un seul appui ne peut jamais fermer deux fenêtres.
- Tant qu'un élément qui possède Retour est ouvert, le Retour Android ne quitte pas l'application (
GoBackPolicycompte les propriétaires et restaurequit_on_go_backaprès le dernier). Votre propre pop-up qui prend Retour doit appelerGoBackPolicy.acquire()etrelease()— dans_exit_treeaussi. - Un tiroir, une visite guidée et un formulaire s'effacent tant qu'une surface est ouverte — Retour va d'abord à la surface.
GoConfig.close_on_back(activé) est l'interrupteur des surfaces.
Qui reçoit un appui
- Une surface couvre tout l'écran et arrête la saisie — un voile transparent aussi. Rien sur un calque inférieur ne peut être pressé tant qu'elle est ouverte ; les calques au-dessus (un snackbar) le peuvent toujours.
- La molette de la souris et le pincement s'arrêtent aussi à la fenêtre : faire défiler au-delà de la fin d'une liste ne fait jamais défiler le jeu.
- La saisie de jeu qui ne passe pas par des commandes —
_unhandled_inputpour le déplacement, un glissement de caméra — doit se mettre en pause :if GoSurface.is_any_open(): return. Cela couvre les boîtes de dialogue, les feuilles, les cartes épinglées et le combobox ; demandezis_open()séparément à un tiroir. - Le snackbar, l'avis, la carte d'invite et le repère guidé ne prennent la saisie que sur leur propre carte ; partout ailleurs, c'est le jeu qui la reçoit.
Focus
Une fenêtre ouverte par un pointeur ne donne le focus à rien — aucun anneau ne clignote pour un toucher. Ouverte depuis un clavier ou une
manette, c'est le bouton de fermeture (ou initial_focus) qui prend le focus. Le focus reste dans la fenêtre tant qu'elle est
ouverte et revient à la commande qui l'avait quand elle se ferme. Les boîtes de dialogue donnent le focus à OK à chaque fois.
Mettre le jeu en pause
Mettre l'arbre en pause met aussi les pop-ups en pause — seule la console continue de fonctionner. Pour un menu de pause, donnez à son calque
process_mode = PROCESS_MODE_ALWAYS ; la fenêtre, ses boutons et Retour continuent alors de tourner pendant que le jeu est arrêté.
Le même pop-up dans chaque apparence
La confirmation du haut de cette page, sur le même jeu, avec seulement le préréglage changé. Le code est identique — le thème, le skin et les icônes font le reste.

default_dark
default_light
scifi_dark
scifi_light
medieval_dark
medieval_light
material_light Nouveau
material_dark Nouveau
kids_light Nouveau
kids_dark Nouveau
comic_light Nouveau
comic_dark Nouveau
arcade_light Nouveau
arcade_dark NouveauCe que change chaque apparence
| Apparence | La fenêtre | Son en-tête et ses boutons |
|---|---|---|
| Par défaut | Arrondie (18dp), une ombre douce, opaque à 80 % par-dessus le jeu | Un titre simple et × ; les boutons principaux se soulèvent et s'enfoncent |
| Science-fiction | Coins coupés avec arête néon et halo, l'arête teintée par l'accent | Marques de focus en crochets |
| Médiéval | Un cadre forgé — fer et cuir, ou parchemin — avec rivets et ornements d'angle | Titres en Cinzel |
| Material 3 | Coins de 28dp, marge intérieure de 24dp, entièrement opaque | Un titre de 24sp en Roboto ; boutons en pilule avec une plaque de 40dp dans une cible de 48dp |
| Enfants | Une carte en bonbon gélifié avec une ombre douce, entièrement opaque | Un ruban de titre ensoleillé (menthe la nuit), un bouton de fermeture rond en bonbon, des boutons qui s'écrasent à l'appui |
| Bande dessinée | Un épais contour d'encre et une ombre franche, entièrement opaque | Un cartouche de titre jaune, un bouton de fermeture rond encré, des boutons dont l'ombre disparaît à l'appui |
| Arcade | Un épais panneau — un cadre coloré autour d'un fond pâle —, entièrement opaque | Un bandeau de titre doré portant un titre blanc cerné d'encre, une touche de fermeture ronde et rouge, des touches peintes qui rebondissent à l'appui |
Habiller un pop-up depuis un skin
Un skin décide des parties qu'un Theme ne peut pas atteindre. Ces hooks sont ceux qu'appellent les pop-ups — redéfinissez-les dans votre propre
sous-classe de GoSkin ; par défaut, ils ne font rien.
| Hook | Ce qu'il habille |
|---|---|
title_plate_box() · title_plate_ink() · title_plate_min_size() | Une plaque derrière le titre d'une fenêtre. Le titre s'y centre et rétrécit, jusqu'à la taille minimale (15), pour tenir sur une ligne. |
dress_close_button(button) | Le × de la fenêtre — l'apparence enfants en fait un bonbon rond, l'apparence bande dessinée un disque encré, l'apparence arcade une touche ronde et rouge. |
dress_title(label) | Le libellé du titre de la fenêtre — l'apparence arcade cerne d'encre son titre blanc. |
press_feedback(control) | S'exécute dès qu'un doigt se pose sur un bouton créé par gohud — l'apparence enfants l'écrase comme une gelée, l'apparence arcade le fait rebondir. |
floating_box() · notice_box() · drawer_box() · banner_box() · overlay_box() | Les faces des cartes d'invite et des cartes de visite guidée, des snackbars et des avis, du tiroir, des bannières, de la console. |
coach_ring_box() · draw_coach_pointer() | L'anneau et le pointeur de la visite guidée. |
Quelle transparence
Chaque type de pop-up suit sa propre opacité, si bien qu'une carte du HUD peut rester légère pendant qu'une boîte de dialogue reste pleine :
les fenêtres, les feuilles, les boîtes de dialogue, les cartes épinglées et le combobox suivent panel_alpha ; le tiroir et la
carte de visite guidée card_alpha ; les cartes d'invite et la console hud_alpha ; les snackbars et les avis
notice_alpha ; les menus popup_alpha. Material et enfants les rendent tous opaques ; la bande dessinée aussi, sauf les cartes d'invite et la console, à 92 %, et l'arcade aussi, sauf ces deux-là, à 94 %. Redéfinissez un type avec
GoConfig.container_alpha_overrides, tous avec container_alpha (un ratio — 0.95), ou une seule fenêtre
avec son alpha. Seule la face s'estompe ; le texte n'est jamais transparent. L'opacité en détail →
Les réglages qui façonnent chaque pop-up
Des champs de GoConfig (GoUi.config). Quelques-uns sont copiés à la création d'une fenêtre : réglez-les
avant de construire l'UI — ou appelez GoUi.refresh() après les avoir changés.
| Champ | Par défaut | Ce qu'il fait |
|---|---|---|
surface_max_width · surface_max_height | 480 · 700 | La taille maximale d'une fenêtre. |
surface_height_ratio · surface_max_height_ratio | 0.68 · 0.72 | La hauteur habituelle et le plafond (aussi la limite de glissement). |
surface_fit_max_height_ratio | 0.94 | Jusqu'où une carte centrée ajustée au contenu peut grandir avant de défiler. |
surface_width_ratio_portrait · …_landscape | 0.94 · 0.72 | La largeur, en part de l'espace disponible. |
dismiss_on_scrim | false | Un appui sur le voile ferme les fenêtres et les boîtes de dialogue. Copié à la création de la fenêtre. |
surface_fade_in · fade_seconds | false · 0.14 | Faire apparaître les fenêtres en fondu, et à quelle vitesse. |
close_on_back | true | Échap, ui_cancel et le Retour Android ferment la fenêtre du dessus. |
close_button_visual | 36 | La taille apparente de × — sa cible tactile reste à 48dp. |
suppress_pointer_focus_ring | true | Pas d'anneau de focus quand une fenêtre est ouverte au toucher ou à la souris. |
container_alpha · container_alpha_overrides | -1 · {} | L'opacité de toutes les faces, ou par type (GoTheme.BOX_*). |
reduce_motion | false | Pas de fondus, de glissements, de pulsations ni d'écrasements. |
min_touch_size | 48 | La hauteur des boutons des cartes d'invite et des repères guidés. |
respect_safe_area | true | Tenir les fenêtres à l'écart de l'encoche et de la barre de gestes. |
text_keys · text_overrides | — | Les mots du kit : fermer, retour, confirmer, annuler, suivant, terminé, passer, rechercher, vide… |
sound_cues · retour haptique | — | Ce que GoFeedback joue à l'ouverture, à la fermeture, à la confirmation, à l'annulation et à l'appui. |
Recettes
Copiez, collez, changez les mots. Chaque appel ici est vérifié par rapport au code source.
Un achat qui affiche le prix
func buy(item_name: String, price: int) -> void:
if await dialogs.confirm("Buy {item}?", "It costs {price} gold.", "Buy", "", "",
{"item": item_name, "price": price}):
purchase(item_name)
Une fenêtre de réglages avec un bouton Enregistrer fixe
func open_settings() -> void:
var layer := CanvasLayer.new()
layer.layer = 50
add_child(layer)
var window := GoSurface.new()
window.set_title("Settings")
window.dismiss_on_scrim = true
window.close_requested.connect(layer.queue_free)
window.body.add_child(GoStyle.section("Sound", false))
window.body.add_child(GoStyle.toggle("Music", false))
window.body.add_child(GoStyle.slider(0.0, 1.0, 0.05))
var row := GoStyle.row()
row.add_child(GoStyle.button("Cancel", window.request_close))
row.add_child(GoStyle.button("Save", func() -> void:
save_settings()
layer.queue_free(), GoStyle.Tone.PRIMARY))
window.footer.add_child(row)
window.footer.visible = true
layer.add_child(window)
Un formulaire qui dit ce qui ne va pas
var field := GoField.make("Name", GoStyle.line_edit(), "3–12 letters")
window.body.add_child(field)
create_button.pressed.connect(func() -> void:
if name_is_taken():
field.set_error("That name is taken")
window.set_status_text("Name check failed", GoTheme.DANGER)
else:
window.clear_status()
create_character())
Une date dans une feuille
sheet.open("Delivery date")
var picker := GoDatePicker.make({"year": 2026, "month": 10, "day": 14}, func(date: Dictionary) -> void:
delivery = date
sheet.close())
picker.min_date = GoDatePicker.today()
sheet.body.add_child(picker)
Un menu de pause
func pause() -> void:
get_tree().paused = true
var layer := CanvasLayer.new()
layer.layer = 50
layer.process_mode = Node.PROCESS_MODE_ALWAYS # continue de tourner pendant que le jeu est en pause
add_child(layer)
var menu := GoSurface.new()
menu.set_title("Paused")
menu.close_requested.connect(func() -> void:
get_tree().paused = false
layer.queue_free())
menu.body.add_child(GoStyle.button("Resume", menu.request_close, GoStyle.Tone.PRIMARY))
menu.body.add_child(GoStyle.button("Settings", open_settings))
menu.body.add_child(GoStyle.button("Quit to title", quit_to_title, GoStyle.Tone.DANGER))
layer.add_child(menu)
Un jeu qui attend les pop-ups
func _unhandled_input(event: InputEvent) -> void:
if GoSurface.is_any_open() or drawer.is_open():
return
handle_gameplay(event)
Pièges
- Un
GoSurfacene se libère jamais lui-même. Connectezclose_requested, sinon × ne fait rien. - Les options réglées après
add_child—scrim_transparent,show_header,resizable,scroll_body, ainsi quelayer_indexetmax_widthdeGoDialogs— ne sont pas appliquées. - Un second
confirm()renvoiefalseimmédiatement. Activezqueue_when_busysi deux questions peuvent se croiser. - Entrée confirme. OK a le focus, y compris dans les boîtes de dialogue destructives.
- Retour sur une feuille ferme la feuille, pas la sous-page.
- Échap ne ferme pas un tiroir, et
is_any_open()ne le voit pas. - Une carte épinglée ou une liste de combobox bloque le jeu jusqu'à sa fermeture, même avec un voile transparent — et une carte épinglée avec
dismissable = falseet sans titre n'a rien à l'écran qui la ferme. - Une carte d'invite démarre masquée et n'expire jamais.
- Un snackbar avec
seconds: 0et sans bouton ne part jamais. Et par défaut, il attrape les appuis sur sa carte. - Un appui long que personne ne connaît est une fonction que personne n'utilise. Affichez aussi un
⋯. - Un arbre en pause met votre pop-up en pause. Utilisez
PROCESS_MODE_ALWAYSsur son calque. - Un avis sans largeur se réduit à sa largeur minimale — utilisez
preferred_width(). - Ne demandez jamais dans un snackbar, n'informez jamais dans une boîte de dialogue. Une question ignorée disparaît ; une nouvelle ne doit pas arrêter le jeu.