Wybierz właściwe okno
Wyskakujące okno przerywa grę. Zanim któreś wybierzesz, odpowiedz na jedno pytanie: czy gracz musi odpowiedzieć, zanim gra pójdzie dalej? Jeśli tak — blokuj. Jeśli nie — nigdy nie blokuj: karta, która zatrzymuje grę dla wiadomości, o którą gracz nie prosił, to najszybszy sposób, żeby zamknął twoją grę.
- Pytanie, na które jest odpowiedź — kup, usuń, wyjdź, nadpisz →
GoDialogs.confirm(). Coś do przyjęcia do wiadomości →alert(). Jedna z kilku opcji →choose(). - Osobny ekran — ustawienia, karta postaci, przedmiot w sklepie →
GoSurfacena środku ekranu. - Długa lista albo strona zarządzania — sakwa, poczta, znajomi →
GoSheetod dołu na telefonie,GoDrawerz boku na szerokim ekranie. - Coś o rzeczy, którą właśnie naciśnięto — statystyki przedmiotu, jego akcje →
GoPopoveralboGoContextMenutuż obok. - Wiadomości, przy których gra może toczyć się dalej — zapisano, wyrzucono, zaproszenie →
GoSnackbar,GoNoticealboGoPromptCard. One nigdy nie zajmują ekranu. - Nauka sterowania →
GoCoachMark. Cheaty w trakcie tworzenia →GoConsole.
Wszystkie okna w skrócie
| Okno | Zatrzymuje grę | Wstecz / Escape | Stuknięcie poza nim | Do czego służy |
|---|---|---|---|---|
GoDialogs confirm · alert | Tak | Zamyka je — confirm odpowiada false, alert wraca | Zamyka je tylko z dismiss_on_scrim | Pytania, które wymagają odpowiedzi |
GoDialogs.choose | Tak | Zamyka je — odpowiada -1 | Zamyka je tylko z dismiss_on_scrim | Wybór jednej z kilku opcji |
GoSurface | Tak | Prosi o zamknięcie najwyższego | Prosi o zamknięcie z dismiss_on_scrim | Twoje własne okna |
GoSheet | Tak | Zamyka cały arkusz | Zamyka go | Sakwa, lista w sklepie, poczta |
GoDrawer | Tak | Tylko androidowe Wstecz | Zamyka go | Lista z boku na szerokim ekranie |
GoPopover | Dopóki się nie zamknie | Zamyka go | Zamyka go — i nie idzie dalej | Szczegóły przedmiotów i umiejętności |
Lista GoCombobox | Dopóki się nie zamknie | Zamyka ją | Zamyka ją | Lista wyboru z wyszukiwaniem |
GoContextMenu · dropdown · select | Menu silnika | Menu silnika | Zamyka je | Akcje, krótkie listy |
GoSnackbar | Nie | — | Trafia do gry | Zapisano · Cofnij · Ponów |
GoPromptCard | Nie | — | Trafia do gry | Zaproszenie, prośba o wymianę |
GoNotice | Nigdy | — | Trafia do gry | Stały wiersz na HUD |
GoBanner | Nie — jest częścią strony | — | — | „Jesteś offline. Ponów” |
GoCoachMark | Tylko jego karta | Kończy przewodnik | Trafia do gry | Przewodnik przy pierwszym uruchomieniu |
GoConsole | Tylko jej panel | Zamyka ją klawisz Escape | Trafia do gry | Komendy debugowania |
Na której warstwie otwiera się każde z nich i dlaczego w tej kolejności — zobacz Warstwy, Wstecz i wejście.

GoDialogs
GoSurface
GoSheet
GoDrawer
GoPopover
GoContextMenu
GoSnackbar
GoPromptCard
GoCoachMark
GoConsoleKażdy obrazek na tej stronie to ta sama mała gra — zdrowie i mana w lewym górnym rogu, monety w prawym górnym, joystick i trzy
szybkie sloty na dole — w default_dark, z jednym otwartym oknem na wierzchu. To samo okno
we wszystkich czternastu wyglądach →
Budowa wyskakującego okna
Niemal każde blokujące okno w gohud — okna dialogowe, arkusze, popovery, lista comboboksa i twoje własne okna — to
jeden węzeł: GoSurface. Poznaj jego części raz, a znasz je wszystkie.

| Część | Czym jest | Jak się do niej dostać |
|---|---|---|
| Warstwa | CanvasLayer, na którym żyje okno. Jej numer decyduje, co okno zakrywa. | W GoSurface wybierasz ją sam; w pozostałych jest wbudowana (tabela) |
| Zasłona | Welon nad wszystkim, co jest z tyłu. Łapie stuknięcia, które chybiły karty. | scrim_transparent, dismiss_on_scrim, kolor scrim motywu |
| Karta | Samo okno — powierzchnia panelu z motywu: zaokrąglona, ścięta, kuta albo galaretkowa, zależnie od wyglądu. | card, alpha |
| Nagłówek | Opcjonalny przycisk wstecz, tytuł (najwyżej dwie linie, potem „…”), przycisk zamknięcia. | set_title() · set_title_key() · set_back() · close_enabled · show_header |
| Pasek narzędzi | Przyklejony wiersz pod nagłówkiem — pole wyszukiwania, chipy filtrów. Ukryty, dopóki go nie użyjesz. | toolbar |
| Ciało | Część przewijana. Tu wkładasz treść. | body · scroll_body · clear() |
| Wiersz stanu | Przyklejony wiersz między ciałem a stopką — „Sprawdzenie imienia nie powiodło się”, „Zapisywanie…”. | set_status_text() · set_status_key() · clear_status() |
| Stopka | Przyklejone przyciski na dole. Ukryta, dopóki jej nie użyjesz. | footer |
toolbar, wiersza stanu i footer; zostają na miejscu, gdy ciało się przewija.
Okna dialogowe, na które czekasz przez await
GoDialogs pyta i czeka. Jeden węzeł, trzy pytania — a odpowiedź wraca w tej samej linii, więc kod czyta
się w kolejności, w jakiej przeżywa to gracz.
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) — nieodwracalne
alert()
choose()
ActionLayout.HORIZONTALTrzy pytania
confirm(title, body, ok_text := "", cancel_text := "", extra := "",
args := {}, destructive := false) -> bool
alert(title, body, ok_text := "", extra := "", args := {}) # użyj await, żeby poczekać
choose(title, options: Array, cancel_text := "", translate := false) -> int
confirm_key(…) · alert_key(…) # klucze tłumaczeń
| Wywołanie | Zwraca | Do czego służy |
|---|---|---|
confirm() | true albo false | Tak albo nie — kup, usuń, wyjdź, nadpisz. |
alert() | nic — użyj await, żeby poczekać | Coś, co gracz musi zobaczyć: nagroda, zerwane połączenie. |
choose() | indeks opcji albo -1 | Jedna z kilku. Opcja to String albo {text, icon, danger, subtitle}. |
confirm_key() · alert_key() | jak wyżej | To samo z kluczami tłumaczeń — słowa podążają za zmianą języka, gdy okno jest otwarte. |
Puste etykiety przycisków wracają do słów samego zestawu (confirm, cancel w GoConfig.text_keys).
extra dopisuje się do treści w nowej linii. args wypełnia {placeholders} w tytule
i w treści: confirm("Buy {item}?", "It costs {price} gold.", "Buy", "", "", {"item": name, "price": 300}).
Każda droga wyjścia ma odpowiedź
| Gracz… | confirm | alert | choose |
|---|---|---|---|
| naciska OK / opcję | true | wraca | indeks opcji |
| naciska Anuluj | false | — | -1 |
| naciska ×, Escape albo androidowe Wstecz | false | wraca | -1 |
stuka w zasłonę (tylko z dismiss_on_scrim) | false | wraca | -1 |
węzeł GoDialogs opuszcza drzewo | false | wraca | -1 |
Dlatego kod po await zawsze się wykona — żadna odpowiedź nie zostaje w zawieszeniu, nawet gdy scena zmieni się pod oknem.
Akcje nieodwracalne
Podaj destructive = true dla czegoś, czego nie da się cofnąć. Przycisk OK staje się wypełnionym przyciskiem
Tone.DANGER_SOLID — biały na czerwonym w każdym wyglądzie, podczas gdy zabarwiona etykieta niebezpieczeństwa musiałaby
w jasnym motywie ściemnieć niemal do czerni, żeby pozostać czytelna. Ton jest resetowany przy każdym wywołaniu, bo okno jest
używane wielokrotnie.
if await dialogs.confirm("Delete this save?", "Slot 2 — Aria, level 12. This cannot be undone.",
"Delete", "Keep it", "", {}, true):
delete_save(2)
Układ przycisków
action_layout | Co robi |
|---|---|
VERTICAL (domyślnie) | Przyciski jeden pod drugim, na całą szerokość. Bezpieczne w każdym języku — długa niemiecka czy rosyjska etykieta nigdy się nie ściśnie. |
HORIZONTAL | Jeden rząd, po połowie szerokości na przycisk. |
AUTO | Jeden rząd tylko wtedy, gdy obie etykiety mieszczą się w połowie karty w jednej linii; w przeciwnym razie jeden pod drugim. Decyzja zapada od nowa po zmianie języka albo rozmiaru. |
action_gap to odstęp między przyciskami, body_gap odstęp nad nimi — zrób go szerszym niż odstęp między
przyciskami, żeby pytanie i wybór czytały się jako dwie części. Dla jednego okna z osobna wywołaj
set_next_action_layout() przed jego otwarciem. Jedyny przycisk alertu zawsze zajmuje całą szerokość.
Jedno naraz
Drugie confirm(), gdy jedno jest otwarte, od razu zwraca false — okno dialogowe nigdy przypadkiem nie
piętrzy się na innym. Włącz queue_when_busy, a zamiast tego poczeka na swoją kolej; alert() czeka zawsze.
queue_limit (8) ogranicza kolejkę, a gdy się przepełni, najstarsze żądanie dostaje odpowiedź false.
pending() liczy oczekujące żądania, a clear_pending() odpowiada na wszystkie false.
choose() nigdy nie czeka w kolejce: zwraca -1, gdy jakieś okno jest już otwarte.
Telefon i komputer
choose() otwiera się jako arkusz od dołu na Androidzie i iOS — tam, gdzie jest kciuk — a na komputerze jako karta
na środku. Potwierdzenie jest ograniczone do max_width (420dp) i wyśrodkowane. Ustaw layer_index,
max_width i pozostałe eksporty przed add_child; nakładane są, gdy węzeł wchodzi do drzewa.
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 — twoje własne okno
Gdy okno to coś więcej niż pytanie — ustawienia, karta postaci, przedmiot do kupienia — zbuduj je na
GoSurface. Bezpieczny obszar, klawiatura, przyklejone wiersze, przewijanie, Wstecz, fokus i zmiana rozmiaru są już zrobione.
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. Ukrycie
albo zwolnienie okna należy do ekranu, który je posiada — tylko on wie, czy „zamknij” znaczy zapisz, odrzuć czy najpierw zapytaj.
Trzy umiejscowienia

CENTER — potwierdzenia, ustawienia
BOTTOM — listy, strony zarządzania
ANCHOR — obok kontrolki
GoDatePicker w oknie CENTERANCHOR potrzebuje anchor_control. Karta trafia na prawo od niej, jeśli zmieści się
anchor_min_width, w przeciwnym razie na szerszą stronę, a w ostateczności do wnętrza ekranu; otwiera się w górę, gdy
nad kotwicą jest więcej miejsca. Podąża za ruchomą kotwicą w każdej klatce. Rozmiar ustalają anchor_width (320) i
anchor_max_height (520).
Jak duże się robi
| Wymiar | Reguła | Czym to zmienić |
|---|---|---|
| Miejsce | Bezpieczny obszar minus klawiatura minus margines ekranu (16dp, nigdy więcej niż 10% krótszego boku). | — |
| Szerokość | 94% miejsca w pionie, 72% w poziomie, najwyżej 480dp. | max_width · GoConfig.surface_width_ratio_* |
| Wysokość | Tak wysokie jak treść (fit_content), do 68% miejsca, z limitem 72%. Wyśrodkowana karta bez zmiany rozmiaru może urosnąć do 94%, żeby uniknąć przewijania. | height_ratio · max_height_ratio · max_height |
| Gęstość | Gęsto, gdy ustawione jest compact, ekran ma mniej niż 420dp wysokości (telefon położony bokiem) albo treść się nie mieści: mniejsze marginesy, mniejsze odstępy, mniejszy tytuł. Mierzy oba warianty i zostawia luźniejszy z tych, które się mieszczą — bez drgania. | compact |
| Zmiana rozmiaru | Z resizable tytuł staje się uchwytem: przeciągaj go między 30% a limitem. Wynik zgłasza height_changed(ratio). | resizable |
Proporcja powyżej limitu jest przycinana, z jednym ostrzeżeniem w kompilacji debugowej. Klawiatura wypycha kartę w górę i przewija pole z fokusem do widoku; bezpieczny obszar trzyma ją z dala od wycięcia i paska gestów na Androidzie i iOS.
Właściwości
| Właściwość | Domyślnie | Co robi |
|---|---|---|
placement | CENTER | CENTER, BOTTOM albo ANCHOR |
dismiss_on_scrim | GoConfig.dismiss_on_scrim (false) | Stuknięcie w zasłonę prosi o zamknięcie. Przeciągnięcie rozpoczęte wewnątrz karty — nie. |
scrim_transparent | false | Gra zostaje widoczna — zasłona nadal łapie stuknięcia poza kartą. |
close_enabled | true | Pokazuje × i pozwala Escape oraz Wstecz prosić o zamknięcie. |
show_header · scroll_body · resizable | true · true · false | Wiersz nagłówka, przewijane ciało, uchwyt do przeciągania. |
fit_content · compact | true · false | Rozmiar według treści; start w trybie gęstym. |
fade_in | GoConfig.surface_fade_in (false) | Karta pojawia się płynnie przy otwarciu. Natychmiast przy reduce_motion. |
alpha | -1 (z motywu) | Krycie powierzchni karty jako proporcja. Blednie tylko powierzchnia — nigdy tekst. |
initial_focus | brak | Kontrolka, która dostaje fokus przy otwarciu. |
add_child: scrim_transparent, show_header, resizable i
scroll_body są nakładane, gdy okno wchodzi do drzewa. dismiss_on_scrim, close_enabled,
fade_in i initial_focus są odczytywane na bieżąco.
Sygnały i wywołania
| Nazwa | Czym jest |
|---|---|
close_requested | ×, Escape, androidowe Wstecz albo stuknięcie w zasłonę — oraz request_close(). Emituje go tylko najwyższe okno. |
back_requested · set_back(action) | Przycisk wstecz w nagłówku, dla okna ze stronami. Pusty Callable go ukrywa. |
height_changed(ratio) | Po przeciągnięciu uchwytu. |
is_top() · GoSurface.is_any_open() | Czy to okno przejmuje Wstecz — czy w ogóle jakieś okno jest otwarte. |
relayout() | Rozmieść ponownie teraz. Zmiana właściwości rozmiaru robi to już za ciebie. |
Arkusze i panele boczne
Lista, która potrzebuje miejsca, wysuwa się od dołu na telefonie trzymanym pionowo — tam, gdzie jest kciuk — a z boku na tablecie albo komputerze, gdzie arkusz zakryłby grę.

GoSheet
GoDrawer · LEFT
GoDrawer · RIGHTGoSheet — strony od dołu
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))
- To
CanvasLayer(warstwa 10) zGoSurfacew umiejscowieniuBOTTOMi ze zmiennym rozmiarem — więc siedzi ponad HUD, a gracz może go przeciągnąć wyżej. open(title)zaczyna nową stronę: czyści ciało, pasek narzędzi i przycisk wstecz oraz zwalnia to, co dodałoadd_footer(). Wywołaj je ponownie, żeby pokazać inną stronę w tym samym arkuszu;set_back()pokazuje przycisk wstecz do powrotu.open_key()przyjmuje klucz tłumaczenia.close()go ukrywa — nie jest zwalniany, więc następneopen()działa natychmiast.closedipage_changedmówią, kiedy to nastąpiło.height_ratio(0.6) to wysokość przy otwarciu;max_height_ratiopodnosi limit;dismissable(true) zamyka arkusz po stuknięciu w zasłonę.
set_back() — o stronę wstecz cofa tylko przycisk wstecz
na ekranie. Jeśli Wstecz ma cofać o krok, obsłuż sam close_requested na sheet.surface.
GoDrawer — z boku
var drawer := GoDrawer.new()
drawer.side = GoDrawer.Side.LEFT
drawer.follow_text_direction = true # strona początku: lewa, po arabsku prawa
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")
- Warstwa 80. 42% szerokości ekranu (
width_ratio), międzymin_width(320dp) amax_width(420dp) — na telefonie zakrywa większość ekranu, i dlatego tam lepszym wyborem jest arkusz. - Panel sięga krawędzi ekranu; tylko jego treść odsuwa się od bezpiecznego obszaru, więc zaokrąglony narożnik nigdy nie utnie pierwszego wiersza.
LEFToznacza lewą stronę ekranu także po arabsku. Włączfollow_text_direction, gdy chodzi o „stronę początku”;effective_side()powie, gdzie panel trafił.open(title)zachowuje ciało — wypełnij je raz.set_title("")ukrywa nagłówek.motion_seconds(0.2) wsuwa panel;reduce_motionsprawia, że pojawia się natychmiast.
drawer.close() z własnego skrótu klawiszowego — i pamiętaj, że GoSurface.is_any_open() nie liczy panelu
bocznego; pytaj drawer.is_open().
Karty i menu obok kontrolki
To, co gracz właśnie nacisnął, zasługuje na odpowiedź tuż przy palcu, a nie na środku ekranu.

GoPopover
GoContextMenu
GoStyle.dropdown()
GoStyle.select()
GoComboboxGoPopover — karta przy naciśniętej rzeczy
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}))
Powierzchnia ANCHOR z już podłączoną warstwą, kotwicą i sprzątaniem — te dziesięć linii, które każda gra pisze wciąż od
nowa. Jedna naraz: otwarcie drugiej zamyka pierwszą, bo karty ułożone w stos grzebią ekran i nikt nie pozna, która należy do
którego slotu. Zasłona jest przezroczysta — karta otwarta po to, by porównać ekwipunek, nie może go przyciemniać — ale nadal łapie
pierwsze stuknięcie poza kartą, które zamyka kartę i nie idzie dalej.
| Opcja | Domyślnie | Co robi |
|---|---|---|
title | "" | Nagłówek z ×. Pusty oznacza brak nagłówka. |
width · max_height | 320 · 520 | Rozmiar karty. |
dismissable | true | Stuknięcie poza kartą ją zamyka. |
compact · alpha · translate | false · -1 · false | Gęste odstępy, krycie powierzchni, tytuł jako klucz tłumaczenia. |
layer | 95 | CanvasLayer, na którym się otwiera. |
GoPopover.close() i GoPopover.is_open() są statyczne. open() zwraca powierzchnię — albo
null, gdy kotwicy nie ma w drzewie, więc sprawdź to, zanim napiszesz await shown.close_requested.
dismissable = false i braku tytułu nic na ekranie jej nie zamknie — tylko Escape, Wstecz albo twoje własne wywołanie.
GoContextMenu — przytrzymanie i prawy przycisk myszy
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))
- Prawy przycisk myszy otwiera je od razu. Palec przytrzymany przez pół sekundy (
HOLD_SECONDS) je otwiera; ruch o więcej niż 12dp anuluje — więc przewijanie listy nigdy nie wyskakuje menu. - Pozycja to
{text, action, icon, disabled, checked, separator, danger, translate}. PodajCallablezamiast tablicy, gdy pozycje zależą od tego, co naciśnięto; wywoływany jest przy każdym otwarciu menu. dangerstawia „⚠ ” przed tekstem — menu silnika potrafi pokolorować tylko wszystkie pozycje naraz.- To silnikowe
PopupMenu, ubrane przezGoStyle.style_popup(). Nie liczy się jako otwarta powierzchnia.
⋯ (open_at(), jak wyżej) albo naucz go raz wskazówką instruktażową.
Listy rozwijane, wybory i przycisk dzielony
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"])
Wszystkie trzy otwierają menu podręczne silnika: dropdown() to MenuButton, który wykonuje akcję,
select() to OptionButton, który przechowuje wartość, a GoSplitButton to główna akcja plus menu pod
strzałką (chosen(index)). Menu są celowo w pełni nieprzezroczyste — menu pokazane we własnym oknie systemu operacyjnego
zamienia półprzezroczyste piksele w czarne.
GoCombobox — lista z wyszukiwaniem
var friend := GoCombobox.make(friend_names, -1, "Find a friend")
friend.picked.connect(func(index: int) -> void: invite(friend_names[index]))
Po naciśnięciu otwiera przypiętą listę na warstwie 96 z przezroczystą zasłoną. Od search_threshold (8) pozycji pojawia
się pole wyszukiwania i przejmuje fokus; dopasowuje w dowolnym miejscu tekstu lub podpowiedzi, bez względu na wielkość liter, a pusty
wynik to komunikuje. Rozmiar listy ustala list_width (0 = szerokość przycisku, co najmniej 180dp).
Okna, które nigdy nie zatrzymują gry
Wiadomości, które gracz może przeczytać w trakcie gry. Żadne z nich nie ma zasłony; stuknięcie gdziekolwiek poza samą kartą trafia do gry.

GoSnackbar
GoNotice
GoPromptCard
GoStyle.tooltip_node()GoSnackbar — komunikat z Cofnij
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)
Klucz post() | Co robi |
|---|---|
text · title · args · translate | Komunikat, opcjonalny pogrubiony wiersz, {placeholders}, klucze tłumaczeń. |
tone · icon | Kolor akcentu (GoTheme.SUCCESS, WARNING…) i ikona. |
actions · closable | Przyciski — Stringi albo {text, action} — oraz ×. |
seconds | Jak długo zostaje. Ujemne: notice_duration_ms z motywu. 0: do zamknięcia — wtedy daj mu przycisk. |
post() zwraca indeks naciśniętego przycisku albo -1, gdy minął czas lub komunikat zamknięto. Wpisy czekają
w kolejce (queue_limit 4, najstarszy wypada z -1), a ten sam tekst wysłany ponownie, gdy jest pokazywany, tylko odnawia
swój licznik czasu. Siedzi na dole (albo u góry — placement), nad bezpiecznym obszarem i klawiaturą, na warstwie 90 —
czytelny ponad panelem bocznym. Z tap_to_dismiss (włączone) stuknięcie w kartę bez przycisków ją zamyka; stuknięcie poza
kartą zawsze trafia do gry. show_text() i show_key() to formy jednolinijkowe.
GoNotice — wiersz na 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)
Zwykły panel, który umieszczasz sam — w GoHudAnchor, w rogu, gdziekolwiek. Nie przejmuje ani wejścia, ani fokusu, więc
naciśnięcie przez niego trafia w przycisk pod spodem, a nowy komunikat zastępuje stary. Nadaj mu szerokość:
preferred_width(limit) zwraca naturalną szerokość krótkiego tekstu, a długi zawija w granicach limit.
set_content() pokazuje dowolną kontrolkę zamiast tekstu.
GoPromptCard — pytanie, które może poczekać
var spot := GoHudAnchor.new()
spot.spot = GoHudAnchor.Spot.TOP_CENTER
spot.reserve_space = false
spot.avoid_peers = true # zejdź pod paski zdrowia, zamiast je zakrywać
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)
- Startuje ukryta — wywołaj
show(). Nie ma własnego licznika czasu; dodaj go, jeśli pytanie wygasa. - Jej przyciski jej nie zamykają — decydują o tym akcje. × (
set_closable(true)) emitujeclosed. fit_width(width)ustawia szerokość i przewiduje wysokość na podstawie czcionki, więc nic, co jest do niej dopasowane, nie podskoczy klatkę później.- Jej powierzchnia podąża za
hud_alpha— to część HUD, nie okno.
GoBanner i podpowiedzi
GoBanner.make("You're offline.", [{"text": "Retry", "action": reconnect}], GoIconSet.WARNING) siedzi w samej stronie,
nad treścią, i nigdy nie wygasa; przycisk go zamyka, chyba że ma "keep": true.
GoStyle.tooltip_node(text) to to, co zwracasz z _make_custom_tooltip() — tło (TooltipPanel)
rysuje silnik, tekst rysuje gohud, z zawijaniem powyżej 260dp. Podpowiedzi są dla myszy; nigdy nie chowaj za nimi czegoś, czego gracz potrzebuje.
Przewodniki i konsola

GoCoachMark
GoConsoleGoCoachMark — przewodnik po prawdziwych kontrolkach
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."}])
- Pierścień wokół prawdziwej kontrolki i karta obok niej. Naciśnięcie celu przesuwa przewodnik dalej (jego sygnał
pressedalbo"signal"w kroku); Dalej i Pomiń są na karcie. Ukryty cel jest pomijany. - Karta trzyma się z dala od środka ekranu (
avoid_center_band), od kotwic HUD i odkeep_clear. - Gdy otwarta jest jakakolwiek
GoSurface, przewodnik się chowa i czeka. Wstecz albo Escape kończy go zfinished(false). - Nie ma własnej warstwy — dodaj go na końcu albo na warstwie ponad HUD.
GoConsole — cheaty w trakcie tworzenia
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()
Warstwa 200 — ponad wszystkim, więc da się debugować na wierzchu okna dialogowego — i działa dalej, gdy drzewo jest wstrzymane. Paleta podpowiada komendy w trakcie pisania; strzałki w górę i w dół przechodzą po historii; Escape ją zamyka. Nie ma wbudowanego klawisza: przypisz własny.
debug_only (włączone) blokuje ją w kompilacji wydania — zarówno open(), jak i run().
Komendy cheatów w rękach gracza kończą ekonomię gry pierwszego dnia.
Warstwy, Wstecz i wejście
Trzy reguły decydują, czego gracz może dotknąć, gdy coś jest otwarte: co jest na wierzchu, do kogo należy Wstecz i kto przyjmuje stuknięcie.
Co jest na wierzchu
| Warstwa | Co na niej siedzi | Czym ustawić |
|---|---|---|
| 5 | Twój HUD (twój wybór) | — |
| 10 | GoSheet | CanvasLayer.layer |
| ~50 | Twoje własne okna GoSurface, menu pauzy | twój CanvasLayer |
| 80 | GoDrawer | CanvasLayer.layer |
| 90 | GoSnackbar | layer_index |
| 95 | GoPopover | opcja "layer" |
| 96 | Lista GoCombobox | — |
| 100 | GoDialogs | layer_index |
| 200 | GoConsole | layer_index |
Kolejność jest celowa: snackbar donosi o tym, co właśnie się stało, więc czyta się go ponad panelem bocznym; popover należy do tego, co właśnie naciśnięto, więc siedzi nad tym; okno dialogowe zadaje pytanie i zakrywa oba; konsola zakrywa wszystko, bo to ją otwierasz, gdy cała reszta zawiodła.
Do kogo należy Wstecz
- Odpowiada tylko najwyższe okno. Spośród otwartych powierzchni ta na najwyższej warstwie (a przy remisie najpóźniejsza w drzewie)
przejmuje Escape, anulowanie z pada (
ui_cancel), androidowe Wstecz i stuknięcia w zasłonę. Okna ułożone w stos zamykają się po jednym, nigdy razem. - Androidowe Wstecz jest obsługiwane klatkę później, więc jedno naciśnięcie nigdy nie zamknie dwóch okien.
- Dopóki otwarte jest cokolwiek, co posiada Wstecz, androidowe Wstecz nie zamyka aplikacji (
GoBackPolicyliczy właścicieli i przywracaquit_on_go_backpo ostatnim). Twoje własne okno, które przejmuje Wstecz, powinno wywołaćGoBackPolicy.acquire()irelease()— także w_exit_tree. - Panel boczny, przewodnik wskazówek i formularz ustępują, gdy otwarta jest powierzchnia — Wstecz trafia najpierw do niej.
GoConfig.close_on_back(włączone) to przełącznik dla powierzchni.
Kto przyjmuje stuknięcie
- Powierzchnia zakrywa cały ekran i zatrzymuje wejście — przezroczysta zasłona także. Gdy jest otwarta, nic na niższej warstwie nie zostanie naciśnięte; warstwy nad nią (snackbar) — nadal tak.
- Kółko myszy i gest szczypania też zatrzymują się na oknie: przewinięcie poza koniec listy nigdy nie przewija gry.
- Wejście rozgrywki, które nie przechodzi przez kontrolki —
_unhandled_inputdo ruchu, przeciąganie kamery — powinno się wstrzymać:if GoSurface.is_any_open(): return. To obejmuje okna dialogowe, arkusze, popovery i combobox; panel boczny zapytaj osobno przezis_open(). - Snackbar, powiadomienie, karta pytania i wskazówka instruktażowa przyjmują wejście tylko na własnej karcie; wszędzie indziej dostaje je gra.
Fokus
Okno otwarte wskaźnikiem nie daje nikomu fokusu — przy dotyku nie miga żaden pierścień. Otwarte z klawiatury albo pada przekazuje fokus
przyciskowi zamknięcia (albo initial_focus). Fokus zostaje wewnątrz okna, dopóki jest otwarte, i wraca do kontrolki, która go
miała, gdy okno się zamknie. Okna dialogowe za każdym razem dają fokus przyciskowi OK.
Wstrzymywanie gry
Wstrzymanie drzewa wstrzymuje też okna — działa dalej tylko konsola. Dla menu pauzy nadaj jego warstwie
process_mode = PROCESS_MODE_ALWAYS; wtedy okno, jego przyciski i Wstecz działają, gdy gra stoi.
To samo okno w każdym wyglądzie
Potwierdzenie z początku tej strony, nad tą samą grą, ze zmienionym tylko presetem. Kod jest identyczny — resztę robią motyw, skórka i ikony.

default_dark
default_light
scifi_dark
scifi_light
medieval_dark
medieval_light
material_light Nowość
material_dark Nowość
kids_light Nowość
kids_dark Nowość
comic_light Nowość
comic_dark Nowość
arcade_light Nowość
arcade_dark NowośćCo zmienia każdy wygląd
| Wygląd | Okno | Jego nagłówek i przyciski |
|---|---|---|
| Domyślny | Zaokrąglone (18dp), miękki cień, 80% krycia nad grą | Zwykły tytuł i ×; przyciski główne unoszą się i zapadają |
| Sci-fi | Ścięte narożniki z neonową krawędzią i poświatą, krawędź zabarwiona akcentem | Znaczniki fokusu w kształcie nawiasów |
| Średniowieczny | Kuta rama — żelazo i skóra albo pergamin — z nitami i ornamentami narożnymi | Tytuły w Cinzel |
| Material 3 | Narożniki 28dp, margines 24dp, w pełni nieprzezroczyste | Nagłówek 24sp w Roboto; przyciski-pigułki z płytką 40dp w obszarze dotyku 48dp |
| Kids | Galaretkowo-cukierkowa karta z miękkim cieniem, w pełni nieprzezroczysta | Słoneczna wstęga tytułu (nocą miętowa), okrągły cukierkowy przycisk zamknięcia, przyciski, które zgniatają się po naciśnięciu |
| Comic | Gruby obrys tuszem i twardy cień, w pełni nieprzezroczyste | Żółte pole tytułu, okrągły przycisk zamknięcia obrysowany tuszem, przyciski, których cień znika po naciśnięciu |
| Arcade | Gruba plansza — kolorowa rama wokół jasnego wnętrza — w pełni nieprzezroczysta | Złota wstęga tytułu z białym tytułem obrysowanym tuszem, okrągły czerwony klawisz zamknięcia, malowane klawisze, które wyskakują po naciśnięciu |
Ubierz okno ze skórki
Skórka decyduje o częściach, do których motyw nie sięga. Te haki wywołują okna — nadpisz je we własnej podklasie
GoSkin; domyślnie nic nie robią.
| Hak | Co ubiera |
|---|---|
title_plate_box() · title_plate_ink() · title_plate_min_size() | Płytka za tytułem okna. Tytuł centruje się na niej i zmniejsza, aż do minimalnego rozmiaru (15), żeby zmieścić się w jednej linii. |
dress_close_button(button) | × okna — Kids robi z niego okrągły cukierek, Comic — krążek obrysowany tuszem, Arcade — okrągły czerwony klawisz. |
dress_title(label) | Etykieta tytułu okna — Arcade obrysowuje jej biały tytuł tuszem. |
press_feedback(control) | Uruchamia się w chwili, gdy palec dotknie przycisku zrobionego przez gohud — Kids go zgniata, Arcade sprawia, że wyskakuje. |
floating_box() · notice_box() · drawer_box() · banner_box() · overlay_box() | Powierzchnie kart pytań i kart przewodnika, snackbarów i powiadomień, panelu bocznego, banerów i konsoli. |
coach_ring_box() · draw_coach_pointer() | Pierścień i wskaźnik przewodnika. |
Jak bardzo prześwitują
Każdy rodzaj okna ma własne krycie, więc karta HUD może zostać lekka, a okno dialogowe pełne: okna, arkusze, okna dialogowe, popovery
i combobox idą za panel_alpha; panel boczny i karta przewodnika za card_alpha; karty pytań i konsola za
hud_alpha; snackbary i powiadomienia za notice_alpha; menu za popup_alpha. Material i Kids robią
je wszystkie nieprzezroczystymi; Comic też, poza kartami pytań i konsolą, które mają 92%, a Arcade też, poza tymi dwoma, które mają 94%. Nadpisz jeden rodzaj przez GoConfig.container_alpha_overrides, wszystkie przez
container_alpha (proporcja — 0.95), a jedno okno przez jego alpha. Blednie tylko powierzchnia;
tekst nigdy nie prześwituje. Krycie szczegółowo →
Ustawienia, które kształtują każde okno
Pola GoConfig (GoUi.config). Kilka z nich jest kopiowanych przy tworzeniu okna, więc ustaw je
przed zbudowaniem interfejsu — albo wywołaj GoUi.refresh() po ich zmianie.
| Pole | Domyślnie | Co robi |
|---|---|---|
surface_max_width · surface_max_height | 480 · 700 | Największy rozmiar okna. |
surface_height_ratio · surface_max_height_ratio | 0.68 · 0.72 | Zwykła wysokość i limit (także limit przeciągania). |
surface_fit_max_height_ratio | 0.94 | Do jakiej wysokości wyśrodkowana karta dopasowana do treści może urosnąć, zanim zacznie się przewijać. |
surface_width_ratio_portrait · …_landscape | 0.94 · 0.72 | Szerokość jako część miejsca. |
dismiss_on_scrim | false | Stuknięcie w zasłonę zamyka okna i okna dialogowe. Kopiowane przy tworzeniu okna. |
surface_fade_in · fade_seconds | false · 0.14 | Płynne pojawianie się okien i jego szybkość. |
close_on_back | true | Escape, ui_cancel i androidowe Wstecz zamykają najwyższe okno. |
close_button_visual | 36 | Jak duży wydaje się × — jego obszar dotyku zostaje 48dp. |
suppress_pointer_focus_ring | true | Bez pierścienia fokusu, gdy okno otwarto dotykiem albo myszą. |
container_alpha · container_alpha_overrides | -1 · {} | Krycie każdej powierzchni albo osobno dla rodzaju (GoTheme.BOX_*). |
reduce_motion | false | Bez zanikania, wsuwania, pulsowania i zgniatania. |
min_touch_size | 48 | Wysokość przycisków na kartach pytań i wskazówkach instruktażowych. |
respect_safe_area | true | Trzyma okna z dala od wycięcia i paska gestów. |
text_keys · text_overrides | — | Słowa samego zestawu: zamknij, wstecz, potwierdź, anuluj, dalej, gotowe, pomiń, szukaj, pusto… |
sound_cues · wibracje | — | Co GoFeedback odtwarza przy otwarciu, zamknięciu, potwierdzeniu, anulowaniu i stuknięciu. |
Przepisy
Skopiuj, wklej, zmień słowa. Każde wywołanie tutaj jest sprawdzone ze źródłem.
Zakup z ceną w treści
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)
Okno ustawień z przyklejonym Zapisz
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)
Formularz, który mówi, co jest nie tak
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())
Data w arkuszu
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)
Menu pauzy
func pause() -> void:
get_tree().paused = true
var layer := CanvasLayer.new()
layer.layer = 50
layer.process_mode = Node.PROCESS_MODE_ALWAYS # działa dalej, gdy gra jest wstrzymana
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)
Rozgrywka, która czeka na okna
func _unhandled_input(event: InputEvent) -> void:
if GoSurface.is_any_open() or drawer.is_open():
return
handle_gameplay(event)
Pułapki
GoSurfacenigdy nie zwalnia się sama. Podłączclose_requested, inaczej × nic nie zrobi.- Opcje ustawione po
add_child—scrim_transparent,show_header,resizable,scroll_bodyorazlayer_indeximax_widthwGoDialogs— nie zostaną nałożone. - Drugie
confirm()od razu zwracafalse. Włączqueue_when_busy, jeśli dwa pytania mogą się spotkać. - Enter potwierdza. Fokus ma OK, także w nieodwracalnych oknach.
- Wstecz na arkuszu zamyka arkusz, a nie podstronę.
- Escape nie zamyka panelu bocznego, a
is_any_open()go nie widzi. - Popover albo lista comboboksa blokuje grę, dopóki się nie zamknie, nawet z przezroczystą zasłoną — a popovera z
dismissable = falsei bez tytułu nie zamknie nic na ekranie. - Karta pytania startuje ukryta i nie wygasa.
- Snackbar z
seconds: 0i bez przycisku nigdy nie zniknie. Do tego domyślnie łapie stuknięcia w swoją kartę. - Przytrzymanie, o którym nikt nie wie, to funkcja, której nikt nie używa. Pokaż też
⋯. - Wstrzymane drzewo wstrzymuje twoje okno. Użyj
PROCESS_MODE_ALWAYSna jego warstwie. - Powiadomienie bez szerokości kurczy się do najwęższej postaci — użyj
preferred_width(). - Nigdy nie pytaj w snackbarze, nigdy nie informuj w oknie dialogowym. Zignorowane pytanie znika; wiadomość nie powinna zatrzymywać gry.