Scegliere il popup giusto
Ogni finestra a comparsa interrompe. Prima di sceglierne uno, rispondi a una sola domanda: chi gioca deve rispondere prima che il gioco vada avanti? Se sì, blocca. Se no, non bloccare mai — una scheda che ferma il gioco per una notizia che nessuno ha chiesto è il modo più rapido per far chiudere il tuo gioco.
- Una domanda che vuole una risposta — comprare, eliminare, uscire, sovrascrivere →
GoDialogs.confirm(). Qualcosa di cui prendere atto →alert(). Una tra poche opzioni →choose(). - Una schermata a sé — le impostazioni, una scheda personaggio, un articolo del negozio →
GoSurfaceal centro dello schermo. - Una lista lunga o una pagina di gestione — la borsa, la posta, gli amici →
GoSheetdal basso su un telefono,GoDrawerdi lato su uno schermo largo. - Qualcosa su ciò che è appena stato premuto — le statistiche di un oggetto, le sue azioni →
GoPopoveroGoContextMenulì accanto. - Notizie durante le quali il gioco può andare avanti — salvato, lasciato cadere, invitato →
GoSnackbar,GoNoticeoGoPromptCard. Questi non occupano mai lo schermo. - Insegnare i controlli →
GoCoachMark. Cheat mentre sviluppi →GoConsole.
Tutti i popup a colpo d'occhio
| Popup | Ferma il gioco | Indietro / Esc | Un tocco fuori | Usalo per |
|---|---|---|---|---|
GoDialogs confirm · alert | Sì | La chiude — confirm risponde false, alert ritorna | La chiude solo con dismiss_on_scrim | Domande che richiedono una risposta |
GoDialogs.choose | Sì | La chiude — risponde -1 | La chiude solo con dismiss_on_scrim | Sceglierne una tra poche |
GoSurface | Sì | Chiede di chiudere la finestra più in alto | Chiede di chiudere con dismiss_on_scrim | Finestre tutte tue |
GoSheet | Sì | Chiude tutto il foglio | Lo chiude | La borsa, una lista del negozio, la posta |
GoDrawer | Sì | Solo Indietro di Android | Lo chiude | Una lista laterale su uno schermo largo |
GoPopover | Finché non si chiude | La chiude | La chiude — e non va oltre | Dettagli di oggetti e abilità |
GoCombobox lista | Finché non si chiude | La chiude | La chiude | Una lista di scelta con ricerca |
GoContextMenu · dropdown · select | Il menu del motore | Il menu del motore | Lo chiude | Azioni, liste brevi |
GoSnackbar | No | — | Arriva al gioco | Salvato · Annulla · Riprova |
GoPromptCard | No | — | Arriva al gioco | Un invito, una richiesta di scambio |
GoNotice | Mai | — | Arriva al gioco | Una riga fissa sull'HUD |
GoBanner | No — sta dentro la pagina | — | — | "Sei offline. Riprova" |
GoCoachMark | Solo la sua scheda | Termina il tour | Arriva al gioco | Un tour al primo avvio |
GoConsole | Solo il suo pannello | Il tasto Esc la chiude | Arriva al gioco | Comandi di debug |
Su quale livello si apre ciascuno, e perché in quell'ordine, è spiegato in Livelli, Indietro e input.

GoDialogs
GoSurface
GoSheet
GoDrawer
GoPopover
GoContextMenu
GoSnackbar
GoPromptCard
GoCoachMark
GoConsoleOgni immagine di questa pagina mostra lo stesso piccolo gioco — salute e mana in alto a sinistra, monete in alto a destra, un joystick e
tre slot rapidi in basso — in default_dark, con un popup aperto sopra. La stessa
conferma in tutti e quattordici gli aspetti →
Anatomia di un popup
Quasi tutti i popup bloccanti di gohud — finestre di dialogo, fogli, schede ancorate, la lista del combobox e le tue
finestre — sono un solo nodo, GoSurface. Impara le sue parti una volta e le conosci tutte.

| Parte | Che cos'è | Come ci arrivi |
|---|---|---|
| Livello | Il CanvasLayer su cui vive il popup. Il suo numero decide che cosa copre. | Lo scegli tu per un GoSurface; integrato per gli altri (tabella) |
| Velo | Il velo steso su tutto ciò che sta dietro. Cattura i tocchi che mancano la scheda. | scrim_transparent, dismiss_on_scrim, il colore scrim del tema |
| Scheda | La finestra stessa — la superficie del pannello del tema, arrotondata, smussata, forgiata o di gelatina a seconda dell'aspetto. | card, alpha |
| Intestazione | Un pulsante indietro facoltativo, il titolo (al massimo due righe, poi "…"), il pulsante di chiusura. | set_title() · set_title_key() · set_back() · close_enabled · show_header |
| Barra degli strumenti | Una riga fissa sotto l'intestazione — un campo di ricerca, chip di filtro. Nascosta finché non la usi. | toolbar |
| Corpo | La parte che scorre. Il contenuto va qui. | body · scroll_body · clear() |
| Riga di stato | Una riga fissa tra il corpo e il piè di pagina — "Controllo del nome non riuscito", "Salvataggio…". | set_status_text() · set_status_key() · clear_status() |
| Piè di pagina | Pulsanti fissi in basso. Nascosto finché non lo usi. | footer |
toolbar, la riga di stato e footer; restano al loro posto mentre il corpo scorre.
Finestre di dialogo da mettere in await
GoDialogs chiede e aspetta. Un nodo, tre domande — e la risposta torna sulla stessa riga, così il codice
si legge nell'ordine in cui chi gioca lo vive.
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) — distruttiva
alert()
choose()
ActionLayout.HORIZONTALLe tre domande
confirm(title, body, ok_text := "", cancel_text := "", extra := "",
args := {}, destructive := false) -> bool
alert(title, body, ok_text := "", extra := "", args := {}) # await per aspettare
choose(title, options: Array, cancel_text := "", translate := false) -> int
confirm_key(…) · alert_key(…) # chiavi di traduzione
| Chiamata | Restituisce | Usala per |
|---|---|---|
confirm() | true o false | Sì o no — comprare, eliminare, uscire, sovrascrivere. |
alert() | niente — mettila in await per aspettare | Qualcosa che chi gioca deve vedere: una ricompensa, una connessione persa. |
choose() | l'indice dell'opzione, oppure -1 | Una tra poche. Un'opzione è una String o {text, icon, danger, subtitle}. |
confirm_key() · alert_key() | come sopra | Lo stesso con chiavi di traduzione — le parole seguono un cambio di lingua mentre la finestra di dialogo è aperta. |
Le etichette dei pulsanti lasciate vuote ricadono sulle parole del kit (confirm, cancel in GoConfig.text_keys).
extra viene aggiunto al corpo su una nuova riga. args riempie i {placeholders} nel titolo
e nel corpo: confirm("Buy {item}?", "It costs {price} gold.", "Buy", "", "", {"item": name, "price": 300}).
Ogni via d'uscita ha una risposta
| Chi gioca… | confirm | alert | choose |
|---|---|---|---|
| preme OK / un'opzione | true | ritorna | l'indice dell'opzione |
| preme Annulla | false | — | -1 |
| preme ×, Esc o Indietro di Android | false | ritorna | -1 |
tocca il velo (solo con dismiss_on_scrim) | false | ritorna | -1 |
il nodo GoDialogs esce dall'albero | false | ritorna | -1 |
Quindi il codice dopo await viene sempre eseguito — nessuna risposta resta in sospeso, nemmeno quando la scena cambia sotto la finestra di dialogo.
Azioni distruttive
Passa destructive = true per qualcosa di irreversibile. Il pulsante OK diventa il pulsante pieno
Tone.DANGER_SOLID — bianco su rosso in ogni aspetto, laddove un'etichetta di pericolo colorata dovrebbe scurirsi fin quasi
al nero su un tema chiaro per restare leggibile. Il tono viene reimpostato a ogni chiamata, perché la finestra viene riutilizzata.
if await dialogs.confirm("Delete this save?", "Slot 2 — Aria, level 12. This cannot be undone.",
"Delete", "Keep it", "", {}, true):
delete_save(2)
Disposizione dei pulsanti
action_layout | Che cosa fa |
|---|---|
VERTICAL (predefinito) | Pulsanti impilati, a tutta larghezza. Sicuro in ogni lingua — una lunga etichetta in tedesco o in russo non viene mai schiacciata. |
HORIZONTAL | Una riga, metà larghezza ciascuno. |
AUTO | Una riga solo quando entrambe le etichette stanno su una riga in metà scheda; altrimenti impilati. Deciso di nuovo a ogni cambio di lingua o ridimensionamento. |
action_gap è lo spazio tra i pulsanti, body_gap lo spazio sopra di essi — rendilo più ampio dello spazio
tra i pulsanti, così la domanda e la scelta si leggono come due parti. Per una sola finestra di dialogo, chiama
set_next_action_layout() prima di aprirla. L'unico pulsante di un alert occupa sempre tutta la larghezza.
Una alla volta
Una seconda confirm() mentre una è aperta restituisce subito false — una finestra di dialogo non si impila mai
per sbaglio su un'altra. Attiva queue_when_busy e aspetta invece il suo turno; alert() aspetta sempre.
queue_limit (8) limita la coda, e quando trabocca la richiesta più vecchia riceve false.
pending() conta le richieste in attesa e clear_pending() risponde false a tutte.
choose() non si mette mai in coda: restituisce -1 quando una finestra di dialogo è già aperta.
Telefono e desktop
choose() si apre come foglio dal basso su Android e iOS — dove sta il pollice — e come scheda al centro su desktop.
Una conferma è limitata a max_width (420dp) e centrata. Imposta layer_index, max_width e gli
altri export prima di add_child; vengono applicati quando il nodo entra nell'albero.
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 — una finestra tutta tua
Quando un popup è più di una domanda — le impostazioni, una scheda personaggio, un oggetto da comprare — costruiscilo su
GoSurface. Area sicura, tastiera, righe fisse, scorrimento, Indietro, focus e ridimensionamento sono già risolti.
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. Nascondere o liberare
la finestra spetta alla schermata proprietaria — solo lei sa se "chiudi" significa salva, scarta o chiedi prima.
Tre collocazioni

CENTER — conferme, impostazioni
BOTTOM — liste, pagine di gestione
ANCHOR — accanto a un controllo
GoDatePicker in una finestra CENTERANCHOR richiede anchor_control. La scheda va alla sua destra se anchor_min_width ci sta,
altrimenti sul lato più ampio, altrimenti dentro lo schermo, e si apre verso l'alto quando c'è più spazio sopra. Segue un ancoraggio
in movimento a ogni frame. anchor_width (320) e anchor_max_height (520) ne fissano le dimensioni.
Quanto diventa grande
| Misura | Regola | Si cambia con |
|---|---|---|
| Spazio | L'area sicura, meno la tastiera, meno il margine dello schermo (16dp, mai più del 10% del lato corto). | — |
| Larghezza | Il 94% dello spazio in verticale, il 72% in orizzontale, al massimo 480dp. | max_width · GoConfig.surface_width_ratio_* |
| Altezza | Alta quanto il contenuto (fit_content), fino al 68% dello spazio, con un tetto al 72%. Una scheda centrata non ridimensionabile può crescere fino al 94% per evitare lo scorrimento. | height_ratio · max_height_ratio · max_height |
| Densità | Compatta quando compact è impostato, quando lo schermo è alto meno di 420dp (un telefono in orizzontale) o quando il contenuto non ci sta: meno margine interno, spazi più piccoli, un titolo più piccolo. Misura entrambe le versioni e tiene la più ariosa che ci sta — senza sfarfallii. | compact |
| Ridimensionamento | Con resizable, il titolo fa da maniglia: trascinalo tra il 30% e il tetto. height_changed(ratio) riporta il risultato. | resizable |
Un rapporto oltre il tetto viene ridotto, con un solo avviso in una build di debug. La tastiera spinge la scheda verso l'alto e fa scorrere il campo con il focus finché non è visibile; l'area sicura la tiene lontana dal notch e dalla barra dei gesti su Android e iOS.
Proprietà
| Proprietà | Predefinito | Che cosa fa |
|---|---|---|
placement | CENTER | CENTER, BOTTOM o ANCHOR |
dismiss_on_scrim | GoConfig.dismiss_on_scrim (false) | Un tocco sul velo chiede la chiusura. Un trascinamento iniziato dentro la scheda no. |
scrim_transparent | false | Lascia il gioco visibile — il velo cattura comunque i tocchi esterni. |
close_enabled | true | Mostra × e lascia che Esc e Indietro chiedano la chiusura. |
show_header · scroll_body · resizable | true · true · false | La riga di intestazione, il corpo scorrevole, la maniglia di trascinamento. |
fit_content · compact | true · false | Adatta la dimensione al contenuto; parti in modalità compatta. |
fade_in | GoConfig.surface_fade_in (false) | Fa apparire la scheda in dissolvenza all'apertura. Istantaneo con reduce_motion. |
alpha | -1 (quella del tema) | L'opacità della superficie della scheda, come rapporto. Sbiadisce solo la superficie — mai il testo. |
initial_focus | nessuno | Il controllo che riceve il focus all'apertura. |
add_child: scrim_transparent, show_header, resizable e
scroll_body vengono applicate quando la finestra entra nell'albero. dismiss_on_scrim, close_enabled,
fade_in e initial_focus vengono lette in tempo reale.
Segnali e chiamate
| Nome | Che cos'è |
|---|---|
close_requested | ×, Esc, Indietro di Android o un tocco sul velo — e request_close(). Emesso solo dalla finestra più in alto. |
back_requested · set_back(action) | Il pulsante indietro dell'intestazione, per una finestra con più pagine. Un Callable vuoto lo nasconde. |
height_changed(ratio) | Dopo un trascinamento della maniglia. |
is_top() · GoSurface.is_any_open() | È questa la finestra che riceve Indietro — c'è almeno una finestra aperta. |
relayout() | Ricalcola subito la disposizione. Cambiare una proprietà di dimensionamento lo fa già per te. |
Fogli e pannelli laterali
Una lista che ha bisogno di spazio sale dal basso su un telefono tenuto in verticale — dove sta il pollice — e arriva di lato su un tablet o un desktop, dove un foglio coprirebbe il gioco.

GoSheet
GoDrawer · LEFT
GoDrawer · RIGHTGoSheet — pagine dal basso
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))
- È un
CanvasLayer(livello 10) che contiene unGoSurfaceBOTTOMridimensionabile — quindi sta sopra l'HUD, e chi gioca può trascinarlo per allungarlo. open(title)inizia una pagina nuova: svuota il corpo, la barra degli strumenti e il pulsante indietro e libera ciò cheadd_footer()ha aggiunto. Richiamalo per mostrare un'altra pagina nello stesso foglio;set_back()mostra un pulsante indietro per tornare alla pagina iniziale.open_key()accetta una chiave di traduzione.close()lo nasconde — non viene liberato, quindi l'open()successivo è istantaneo.closedepage_changedti dicono quando succede.height_ratio(0.6) è l'altezza di apertura;max_height_ratioalza il tetto;dismissable(true) lo chiude con un tocco sul velo.
set_back() — solo il pulsante indietro sullo schermo
torna di una pagina. Se Indietro deve tornare di una pagina, gestisci tu close_requested su sheet.surface.
GoDrawer — di lato
var drawer := GoDrawer.new()
drawer.side = GoDrawer.Side.LEFT
drawer.follow_text_direction = true # il lato d'inizio: sinistra, oppure destra in arabo
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")
- Livello 80. Largo il 42% dello schermo (
width_ratio), tramin_width(320dp) emax_width(420dp) — su un telefono copre quasi tutto lo schermo, ed è per questo che lì un foglio è la scelta migliore. - Il pannello arriva fino al bordo dello schermo; solo il suo contenuto rientra dall'area sicura, così un angolo arrotondato non taglia mai la prima riga.
LEFTsignifica sinistra dello schermo anche in arabo. Attivafollow_text_directionquando il punto è "il lato d'inizio";effective_side()ti dice da che parte è finito.open(title)mantiene il corpo — riempilo una volta sola.set_title("")nasconde l'intestazione.motion_seconds(0.2) lo fa scorrere;reduce_motionlo rende istantaneo.
drawer.close() da una tua scorciatoia da tastiera — e nota che GoSurface.is_any_open() non conta i pannelli laterali;
chiedi a drawer.is_open().
Schede e menu accanto a un controllo
Ciò che chi gioca ha appena premuto merita una risposta proprio accanto al dito, non al centro dello schermo.

GoPopover
GoContextMenu
GoStyle.dropdown()
GoStyle.select()
GoComboboxGoPopover — una scheda su ciò che hai premuto
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}))
Una superficie ANCHOR con livello, ancoraggio e smontaggio già collegati — le dieci righe che ogni gioco riscrive una volta
dopo l'altra. Una alla volta: aprirne una seconda chiude la prima, perché le schede impilate seppelliscono lo schermo e nessuno
capisce più quale appartenga a quale slot. Il velo è trasparente — una scheda aperta per confrontare l'equipaggiamento non deve oscurare
l'equipaggiamento — ma cattura comunque il primo tocco esterno, che chiude la scheda e non va oltre.
| Opzione | Predefinito | Che cosa fa |
|---|---|---|
title | "" | Un'intestazione con ×. Vuoto: nessuna intestazione. |
width · max_height | 320 · 520 | La dimensione della scheda. |
dismissable | true | Un tocco esterno la chiude. |
compact · alpha · translate | false · -1 · false | Spaziatura compatta, opacità della superficie, titolo come chiave di traduzione. |
layer | 95 | Il CanvasLayer su cui si apre. |
GoPopover.close() e GoPopover.is_open() sono statici. open() restituisce la superficie — oppure
null quando l'ancoraggio non è nell'albero, quindi controlla prima di fare await shown.close_requested.
dismissable = false e senza titolo, niente sullo schermo la chiude — solo Esc, Indietro o una tua chiamata.
GoContextMenu — pressione prolungata e clic destro
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 destro lo apre subito. Un dito tenuto premuto per mezzo secondo (
HOLD_SECONDS) lo apre; spostarsi di più di 12dp annulla — così scorrere una lista non fa mai saltare fuori un menu. - Una voce è
{text, action, icon, disabled, checked, separator, danger, translate}. Passa unCallableinvece dell'array quando le voci dipendono da che cosa è stato premuto; viene chiamato a ogni apertura del menu. dangermette "⚠ " prima del testo — il menu del motore può colorare solo tutte le sue voci insieme.- È il
PopupMenudel motore, vestito daGoStyle.style_popup(). Non conta come superficie aperta.
⋯ visibile
(open_at(), come sopra), oppure insegnala una volta con un coach mark.
Menu a tendina, selettori e pulsante diviso
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"])
Tutti e tre aprono il menu popup del motore: dropdown() è un MenuButton che esegue un'azione,
select() un OptionButton che conserva un valore, GoSplitButton un'azione principale più un menu sulla
sua freccia (chosen(index)). I menu restano completamente opachi di proposito — un menu mostrato in una propria finestra del
sistema operativo rende neri i pixel traslucidi.
GoCombobox — una lista con ricerca
var friend := GoCombobox.make(friend_names, -1, "Find a friend")
friend.picked.connect(func(index: int) -> void: invite(friend_names[index]))
Quando lo premi, apre una lista ancorata sul livello 96 con un velo trasparente. Da search_threshold (8) voci in su compare
un campo di ricerca che prende il focus; trova corrispondenze in qualsiasi punto del testo o del suggerimento, senza distinguere maiuscole
e minuscole, e un risultato vuoto lo segnala. list_width (0 = la larghezza del pulsante, almeno 180dp) dimensiona la lista.
Popup che non fermano mai il gioco
Notizie che chi gioca può leggere mentre gioca. Nessuno di questi ha un velo; un tocco in qualunque punto che non sia la scheda stessa va al gioco.

GoSnackbar
GoNotice
GoPromptCard
GoStyle.tooltip_node()GoSnackbar — un messaggio con Annulla
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)
Chiave di post() | Che cosa fa |
|---|---|
text · title · args · translate | Il messaggio, una riga in grassetto facoltativa, i {placeholders}, le chiavi di traduzione. |
tone · icon | Il colore d'accento (GoTheme.SUCCESS, WARNING…) e un'icona. |
actions · closable | Pulsanti — String o {text, action} — e una ×. |
seconds | Quanto resta visibile. Negativo: il notice_duration_ms del tema. 0: finché non viene chiuso — in quel caso dagli un pulsante. |
post() restituisce l'indice del pulsante premuto, oppure -1 quando è scaduto o è stato chiuso. I messaggi si
mettono in coda (queue_limit 4, il più vecchio scartato con -1), e lo stesso testo inviato di nuovo mentre è visibile si limita
a ricaricare il suo timer. Sta in basso (o in alto, placement), sopra l'area sicura e la tastiera, sul livello 90 — leggibile
sopra un pannello laterale. Con tap_to_dismiss (attivo) un tocco su una scheda senza pulsanti la chiude; un tocco fuori dalla
scheda arriva sempre al gioco. show_text() e show_key() sono le forme in una riga.
GoNotice — una riga sull'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 semplice pannello che posizioni tu — in un GoHudAnchor, in un angolo, ovunque. Non prende né input né focus, quindi
premere attraverso di esso raggiunge il pulsante sottostante, e un nuovo messaggio sostituisce il vecchio. Dagli una larghezza:
preferred_width(limit) restituisce la larghezza naturale di un testo breve e manda a capo un testo lungo entro limit.
set_content() mostra un controllo qualsiasi al posto del testo.
GoPromptCard — una domanda che può aspettare
var spot := GoHudAnchor.new()
spot.spot = GoHudAnchor.Spot.TOP_CENTER
spot.reserve_space = false
spot.avoid_peers = true # scende sotto le barre della salute invece di coprirle
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)
- Parte nascosta — chiama
show(). Non ha un timer suo; aggiungine uno se la domanda scade. - I suoi pulsanti non la chiudono — decidono le azioni. × (
set_closable(true)) emetteclosed. fit_width(width)imposta la larghezza e prevede l'altezza dal font, così niente di ciò che è disposto in base a essa salta un frame dopo.- La sua superficie segue
hud_alpha— fa parte dell'HUD, non è una finestra.
GoBanner e tooltip
GoBanner.make("You're offline.", [{"text": "Retry", "action": reconnect}], GoIconSet.WARNING) sta nella pagina
stessa, sopra il contenuto, e non scade mai; un pulsante lo chiude, a meno che non abbia "keep": true.
GoStyle.tooltip_node(text) è ciò che va restituito da _make_custom_tooltip() — il motore disegna il fondo
(TooltipPanel), gohud il testo, mandato a capo oltre i 260dp. I tooltip sono per il mouse; non nascondere mai dietro un tooltip qualcosa di cui chi gioca ha bisogno.
Tour e console

GoCoachMark
GoConsoleGoCoachMark — un tour dei controlli veri
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 anello intorno al controllo vero e una scheda accanto. Premere il bersaglio fa avanzare (il suo segnale
pressed, oppure"signal"nel passaggio); Avanti e Salta sono sulla scheda. Un bersaglio nascosto viene saltato. - La scheda resta fuori dal centro dello schermo (
avoid_center_band), lontana dagli ancoraggi dell'HUD e dakeep_clear. - Finché un
GoSurfaceè aperto, il tour si nasconde e aspetta. Indietro o Esc lo terminano confinished(false). - Non ha un livello suo — aggiungilo per ultimo, oppure su un livello sopra l'HUD.
GoConsole — cheat mentre sviluppi
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()
Livello 200 — sopra ogni cosa, così puoi fare debug sopra una finestra di dialogo — e continua a funzionare mentre l'albero è in pausa. Una palette suggerisce i comandi mentre digiti; Su e Giù scorrono la cronologia; Esc la chiude. Non c'è un tasto predefinito: assegnane uno tu.
debug_only (attivo) la blocca in una build di rilascio — sia open() sia run(). I comandi di
cheat nelle mani di chi gioca chiudono l'economia di un gioco il primo giorno.
Livelli, Indietro e input
Tre regole decidono che cosa chi gioca può toccare mentre qualcosa è aperto: che cosa sta sopra, a chi appartiene Indietro e chi riceve un tocco.
Che cosa sta sopra
| Livello | Che cosa ci sta | Si imposta con |
|---|---|---|
| 5 | Il tuo HUD (a tua scelta) | — |
| 10 | GoSheet | CanvasLayer.layer |
| ~50 | Le tue finestre GoSurface, un menu di pausa | il tuo CanvasLayer |
| 80 | GoDrawer | CanvasLayer.layer |
| 90 | GoSnackbar | layer_index |
| 95 | GoPopover | opzione "layer" |
| 96 | lista di GoCombobox | — |
| 100 | GoDialogs | layer_index |
| 200 | GoConsole | layer_index |
L'ordine è voluto: uno snackbar riferisce ciò che è appena successo, quindi si legge sopra un pannello laterale; una scheda ancorata appartiene a ciò che è appena stato premuto, quindi gli sta sopra; una finestra di dialogo fa una domanda e copre entrambi; la console copre tutto, perché è ciò che apri quando tutto il resto è andato storto.
A chi appartiene Indietro
- Risponde solo la finestra più in alto. Tra le superfici aperte, quella sul livello più alto (poi l'ultima nell'albero) riceve
Esc, l'annullamento del gamepad (
ui_cancel), Indietro di Android e i tocchi sul velo. Le finestre impilate si chiudono una alla volta, mai insieme. - Indietro di Android viene gestito un frame dopo, così una sola pressione non può mai chiudere due finestre.
- Finché è aperto qualcosa che possiede Indietro, Indietro di Android non chiude l'app (
GoBackPolicyconta i proprietari e ripristinaquit_on_go_backdopo l'ultimo). Un tuo popup che prende Indietro deve chiamareGoBackPolicy.acquire()erelease()— anche in_exit_tree. - Un pannello laterale, un tour con coach mark e un modulo si fanno da parte mentre una superficie è aperta — Indietro va prima alla superficie.
GoConfig.close_on_back(attivo) è l'interruttore per le superfici.
Chi riceve un tocco
- Una superficie copre tutto lo schermo e ferma l'input — anche con un velo trasparente. Niente su un livello inferiore viene premuto mentre è aperta; i livelli sopra (uno snackbar) sì.
- Anche la rotella del mouse e il gesto di pizzico si fermano alla finestra: scorrere oltre la fine di una lista non fa mai scorrere il gioco.
- L'input di gioco che non passa dai controlli —
_unhandled_inputper il movimento, un trascinamento della telecamera — deve mettersi in pausa:if GoSurface.is_any_open(): return. Questo copre finestre di dialogo, fogli, schede ancorate e il combobox; a un pannello laterale chiediis_open()a parte. - Snackbar, avviso, prompt card e coach mark prendono l'input solo sulla propria scheda; ovunque altro lo riceve il gioco.
Focus
Una finestra aperta da un puntatore non mette il focus su niente — nessun anello lampeggia per un tocco. Se è aperta da tastiera o gamepad,
il focus va al pulsante di chiusura (o a initial_focus). Il focus resta dentro la finestra finché è aperta e torna al controllo
che lo aveva quando la finestra si chiude. Le finestre di dialogo mettono il focus su OK ogni volta.
Mettere in pausa il gioco
Mettere in pausa l'albero mette in pausa anche i popup — solo la console continua a funzionare. Per un menu di pausa, dai al suo livello
process_mode = PROCESS_MODE_ALWAYS; così la finestra, i suoi pulsanti e Indietro continuano a funzionare mentre il gioco è fermo.
Lo stesso popup in ogni aspetto
La conferma di inizio pagina, sopra lo stesso gioco, cambiando solo il preset. Il codice è identico — il tema, la skin e le icone fanno il resto.

default_dark
default_light
scifi_dark
scifi_light
medieval_dark
medieval_light
material_light Nuovo
material_dark Nuovo
kids_light Nuovo
kids_dark Nuovo
comic_light Nuovo
comic_dark Nuovo
arcade_light Nuovo
arcade_dark NuovoChe cosa cambia ogni aspetto
| Aspetto | La finestra | Intestazione e pulsanti |
|---|---|---|
| Default | Arrotondata (18dp), un'ombra morbida, opaca all'80% sopra il gioco | Un titolo semplice e ×; i pulsanti primari si sollevano e affondano |
| Sci-fi | Angoli smussati con bordo al neon e bagliore, il bordo tinto dall'accento | Segni di focus a staffa |
| Medievale | Una cornice forgiata — ferro e cuoio, oppure pergamena — con rivetti e ornamenti angolari | Titoli in Cinzel |
| Material 3 | Angoli da 28dp, margine interno da 24dp, completamente opaca | Un titolo da 24sp in Roboto; pulsanti a pillola con una piastra da 40dp in un'area da 48dp |
| Bambini | Una scheda a caramella di gelatina con un'ombra morbida, completamente opaca | Un nastro del titolo color sole (menta di notte), un pulsante di chiusura tondo a caramella, pulsanti che si schiacciano quando li premi |
| Fumetto | Un contorno d'inchiostro spesso e un'ombra netta, completamente opaca | Una didascalia del titolo gialla, un pulsante di chiusura tondo inchiostrato, pulsanti la cui ombra sparisce quando li premi |
| Arcade | Una plancia spessa — una cornice colorata attorno a un fondo chiaro — completamente opaca | Una fascia del titolo dorata con un titolo bianco contornato d'inchiostro, un tasto di chiusura tondo e rosso, tasti dipinti che scattano quando li premi |
Vestire un popup da una skin
Una skin decide le parti che un Theme non raggiunge. Questi hook sono quelli che chiamano i popup — sovrascrivili nella tua sottoclasse di
GoSkin; per impostazione predefinita non fanno nulla.
| Hook | Che cosa veste |
|---|---|
title_plate_box() · title_plate_ink() · title_plate_min_size() | Una piastra dietro il titolo di una finestra. Il titolo ci si centra sopra e si rimpicciolisce, fino alla dimensione minima (15), per restare su una riga. |
dress_close_button(button) | La × della finestra — l'aspetto bambini la trasforma in una caramella tonda, l'aspetto fumetto in un disco inchiostrato, l'aspetto arcade in un tasto tondo e rosso. |
dress_title(label) | L'etichetta del titolo della finestra — l'aspetto arcade contorna d'inchiostro il suo titolo bianco. |
press_feedback(control) | Viene eseguito nell'istante in cui un dito tocca un pulsante creato da gohud — l'aspetto bambini lo schiaccia, l'aspetto arcade lo fa scattare. |
floating_box() · notice_box() · drawer_box() · banner_box() · overlay_box() | Le superfici delle prompt card e delle schede del coach mark, degli snackbar e degli avvisi, del pannello laterale, dei banner, della console. |
coach_ring_box() · draw_coach_pointer() | L'anello e il puntatore del tour. |
Quanto trasparente
Ogni tipo di popup segue la propria opacità, così una scheda dell'HUD può restare leggera mentre una finestra di dialogo resta piena: finestre,
fogli, finestre di dialogo, schede ancorate e il combobox seguono panel_alpha; il pannello laterale e la scheda del coach mark
card_alpha; le prompt card e la console hud_alpha; snackbar e avvisi notice_alpha; i menu
popup_alpha. Material e bambini li rendono tutti opachi; anche fumetto, tranne le prompt card e la console al 92%, e arcade, tranne queste due al 94%. Sovrascrivi un tipo con GoConfig.container_alpha_overrides,
tutti con container_alpha (un rapporto — 0.95), o una sola finestra con il suo alpha. Sbiadisce solo la
superficie; il testo non è mai trasparente. L'opacità nel dettaglio →
Impostazioni che danno forma a ogni popup
Campi di GoConfig (GoUi.config). Alcuni vengono copiati quando si crea una finestra, quindi impostali
prima di costruire la UI — oppure chiama GoUi.refresh() dopo averli cambiati.
| Campo | Predefinito | Che cosa fa |
|---|---|---|
surface_max_width · surface_max_height | 480 · 700 | La dimensione massima di una finestra. |
surface_height_ratio · surface_max_height_ratio | 0.68 · 0.72 | L'altezza abituale e il tetto (anche il limite di trascinamento). |
surface_fit_max_height_ratio | 0.94 | Fin dove una scheda centrata adattata al contenuto può crescere prima di scorrere. |
surface_width_ratio_portrait · …_landscape | 0.94 · 0.72 | La larghezza come quota dello spazio disponibile. |
dismiss_on_scrim | false | Un tocco sul velo chiude finestre e finestre di dialogo. Copiato quando si crea la finestra. |
surface_fade_in · fade_seconds | false · 0.14 | Dissolvenza in entrata delle finestre, e con quale velocità. |
close_on_back | true | Esc, ui_cancel e Indietro di Android chiudono la finestra più in alto. |
close_button_visual | 36 | Quanto appare grande la × — la sua area di tocco resta di 48dp. |
suppress_pointer_focus_ring | true | Nessun anello di focus quando una finestra viene aperta con il tocco o il mouse. |
container_alpha · container_alpha_overrides | -1 · {} | L'opacità di ogni superficie, o per tipo (GoTheme.BOX_*). |
reduce_motion | false | Niente dissolvenze, scorrimenti, pulsazioni né schiacciamenti. |
min_touch_size | 48 | L'altezza dei pulsanti di prompt card e coach mark. |
respect_safe_area | true | Tiene le finestre lontane dal notch e dalla barra dei gesti. |
text_keys · text_overrides | — | Le parole del kit: chiudi, indietro, conferma, annulla, avanti, fatto, salta, cerca, vuoto… |
sound_cues · feedback aptico | — | Ciò che GoFeedback riproduce all'apertura, alla chiusura, alla conferma, all'annullamento e al tocco. |
Ricette
Copia, incolla, cambia le parole. Ogni chiamata qui è verificata sul codice sorgente.
Un acquisto con il prezzo nel testo
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)
Una finestra di impostazioni con Salva fisso
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 modulo che dice che cosa non va
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())
Una data in un foglio
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 di pausa
func pause() -> void:
get_tree().paused = true
var layer := CanvasLayer.new()
layer.layer = 50
layer.process_mode = Node.PROCESS_MODE_ALWAYS # continua a funzionare mentre il gioco è in pausa
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 gameplay che aspetta i popup
func _unhandled_input(event: InputEvent) -> void:
if GoSurface.is_any_open() or drawer.is_open():
return
handle_gameplay(event)
Trappole
- Un
GoSurfacenon si libera mai da solo. Collegaclose_requested, altrimenti × non fa nulla. - Le opzioni impostate dopo
add_child—scrim_transparent,show_header,resizable,scroll_body, elayer_indexemax_widthdiGoDialogs— non vengono applicate. - Una seconda
confirm()restituisce subitofalse. Attivaqueue_when_busyse due domande possono incrociarsi. - Invio conferma. OK ha il focus, anche nelle finestre di dialogo distruttive.
- Indietro su un foglio chiude il foglio, non la sottopagina.
- Esc non chiude un pannello laterale, e
is_any_open()non lo vede. - Una scheda ancorata o una lista di combobox blocca il gioco finché non si chiude, anche con un velo trasparente — e una scheda ancorata con
dismissable = falsee senza titolo non ha niente sullo schermo che la chiuda. - Una prompt card parte nascosta e non scade mai.
- Uno snackbar con
seconds: 0e senza pulsanti non se ne va mai. E per impostazione predefinita cattura i tocchi sulla sua scheda. - Una pressione prolungata che nessuno conosce è una funzione che nessuno usa. Mostra anche un
⋯. - Un albero in pausa mette in pausa il tuo popup. Usa
PROCESS_MODE_ALWAYSsul suo livello. - Un avviso senza larghezza si restringe al minimo — usa
preferred_width(). - Mai chiedere in uno snackbar, mai informare in una finestra di dialogo. Una domanda ignorata sparisce; una notizia non deve fermare il gioco.