Pilih popup yang tepat
Setiap jendela yang muncul menyela permainan. Sebelum memilihnya, jawab satu pertanyaan saja: haruskah pemain menjawab dulu sebelum game berlanjut? Jika ya, blokir. Jika tidak, jangan pernah memblokir — kartu yang menghentikan game demi kabar yang tidak diminta pemain adalah cara tercepat membuat mereka menutup game Anda.
- Pertanyaan yang butuh jawaban — beli, hapus, keluar, timpa →
GoDialogs.confirm(). Sesuatu yang cukup diketahui →alert(). Satu dari beberapa pilihan →choose(). - Layar tersendiri — setelan, lembar karakter, barang di toko →
GoSurfacedi tengah layar. - Daftar panjang atau halaman pengelolaan — tas, surat, teman →
GoSheetdari bawah di ponsel,GoDrawerdari samping di layar lebar. - Sesuatu tentang benda yang baru ditekan — statistik sebuah item, tindakan-tindakannya →
GoPopoveratauGoContextMenutepat di sampingnya. - Kabar yang tidak perlu menghentikan game — tersimpan, dibuang, diundang →
GoSnackbar,GoNotice, atauGoPromptCard. Semua ini tidak pernah mengambil alih layar. - Mengajarkan kontrol →
GoCoachMark. Cheat selama pengembangan →GoConsole.
Semua popup dalam satu tabel
| Popup | Menghentikan game | Back / Escape | Ketukan di luar | Dipakai untuk |
|---|---|---|---|---|
GoDialogs confirm · alert | Ya | Menutupnya — confirm menjawab false, alert kembali | Menutupnya hanya dengan dismiss_on_scrim | Pertanyaan yang butuh jawaban |
GoDialogs.choose | Ya | Menutupnya — menjawab -1 | Menutupnya hanya dengan dismiss_on_scrim | Memilih satu dari beberapa |
GoSurface | Ya | Meminta jendela teratas ditutup | Meminta tutup dengan dismiss_on_scrim | Jendela buatan Anda sendiri |
GoSheet | Ya | Menutup seluruh lembar | Menutupnya | Tas, daftar toko, surat |
GoDrawer | Ya | Hanya tombol Kembali Android | Menutupnya | Daftar samping di layar lebar |
GoPopover | Sampai ditutup | Menutupnya | Menutupnya — dan tidak diteruskan | Rincian item dan skill |
Daftar GoCombobox | Sampai ditutup | Menutupnya | Menutupnya | Daftar pilihan yang bisa dicari |
GoContextMenu · dropdown · kotak pilihan | Menu milik engine | Menu milik engine | Menutupnya | Tindakan, daftar pendek |
GoSnackbar | Tidak | — | Sampai ke game | Tersimpan · Urungkan · Coba lagi |
GoPromptCard | Tidak | — | Sampai ke game | Undangan, permintaan tukar barang |
GoNotice | Tidak pernah | — | Sampai ke game | Satu baris tetap di HUD |
GoBanner | Tidak — ia berada di dalam halaman | — | — | "Anda sedang offline. Coba lagi" |
GoCoachMark | Hanya kartunya | Mengakhiri tur | Sampai ke game | Tur saat pertama kali dijalankan |
GoConsole | Hanya panelnya | Tombol Escape menutupnya | Sampai ke game | Perintah debug |
Di lapisan mana masing-masing terbuka, dan mengapa urutannya begitu, dijelaskan di Lapisan, Kembali, dan input.

GoDialogs
GoSurface
GoSheet
GoDrawer
GoPopover
GoContextMenu
GoSnackbar
GoPromptCard
GoCoachMark
GoConsoleSetiap gambar di halaman ini adalah game kecil yang sama — darah dan mana di kiri atas, koin di kanan atas, joystick dan tiga
slot cepat di bawah — dalam default_dark, dengan satu popup terbuka di atasnya. Popup yang sama
dalam keempat belas tampilan →
Anatomi sebuah popup
Hampir semua jendela yang memblokir di gohud — dialog, lembar, popover, daftar combobox, dan jendela buatan Anda
sendiri — adalah satu node, GoSurface. Pelajari bagian-bagiannya sekali dan Anda mengenal semuanya.

| Bagian | Apa itu | Cara menjangkaunya |
|---|---|---|
| Lapisan | CanvasLayer tempat popup itu berada. Angkanya menentukan apa yang ditutupinya. | Milik Anda untuk GoSurface; bawaan untuk yang lain (tabel) |
| Selubung | Tirai di atas semua yang ada di belakang. Ia menangkap ketukan yang meleset dari kartu. | scrim_transparent, dismiss_on_scrim, warna scrim dari tema |
| Kartu | Jendelanya sendiri — muka panel dari tema, membulat, terpotong, tempaan, atau jeli tergantung tampilannya. | card, alpha |
| Header | Tombol kembali opsional, judul (paling banyak dua baris, lalu "…"), tombol tutup. | set_title() · set_title_key() · set_back() · close_enabled · show_header |
| Bilah alat | Baris yang menempel di bawah header — kolom pencarian, chip filter. Tersembunyi sampai Anda memakainya. | toolbar |
| Body | Bagian yang bergulir. Taruh kontennya di sini. | body · scroll_body · clear() |
| Baris status | Baris yang menempel di antara body dan footer — "Pemeriksaan nama gagal", "Menyimpan…". | set_status_text() · set_status_key() · clear_status() |
| Footer | Tombol-tombol yang menempel di bawah. Tersembunyi sampai Anda memakainya. | footer |
toolbar, baris status, dan footer; ketiganya diam di tempat sementara body bergulir.
Dialog yang Anda await
GoDialogs bertanya lalu menunggu. Satu node, tiga jenis pertanyaan — dan jawabannya kembali di baris
yang sama, sehingga kodenya terbaca sesuai urutan yang dialami pemain.
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) — destruktif
alert()
choose()
ActionLayout.HORIZONTALTiga jenis pertanyaan
confirm(title, body, ok_text := "", cancel_text := "", extra := "",
args := {}, destructive := false) -> bool
alert(title, body, ok_text := "", extra := "", args := {}) # await untuk menunggunya
choose(title, options: Array, cancel_text := "", translate := false) -> int
confirm_key(…) · alert_key(…) # kunci terjemahan
| Pemanggilan | Mengembalikan | Dipakai untuk |
|---|---|---|
confirm() | true atau false | Ya atau tidak — beli, hapus, keluar, timpa. |
alert() | tidak ada — await untuk menunggunya | Sesuatu yang wajib dilihat pemain: hadiah, koneksi yang terputus. |
choose() | indeks pilihannya, atau -1 | Satu dari beberapa. Sebuah pilihan berupa String atau {text, icon, danger, subtitle}. |
confirm_key() · alert_key() | sama seperti di atas | Sama, tetapi dengan kunci terjemahan — teksnya ikut berganti saat bahasa diganti selagi dialog terbuka. |
Label tombol yang kosong kembali ke kata-kata milik kit sendiri (confirm, cancel di GoConfig.text_keys).
extra ditambahkan ke body pada baris baru. args mengisi {placeholders} di judul
dan body: confirm("Buy {item}?", "It costs {price} gold.", "Buy", "", "", {"item": name, "price": 300}).
Setiap jalan keluar punya jawaban
| Pemain… | confirm | alert | choose |
|---|---|---|---|
| menekan OK / sebuah pilihan | true | kembali | indeks pilihannya |
| menekan Batal | false | — | -1 |
| menekan ×, Escape, atau tombol Kembali Android | false | kembali | -1 |
mengetuk selubung (hanya dengan dismiss_on_scrim) | false | kembali | -1 |
node GoDialogs keluar dari tree | false | kembali | -1 |
Jadi kode setelah await selalu berjalan — tak ada jawaban yang dibiarkan menggantung, bahkan ketika scene berganti di bawah dialognya.
Tindakan yang tak bisa dibatalkan
Berikan destructive = true untuk sesuatu yang tidak bisa dibatalkan. Tombol OK berubah menjadi tombol
Tone.DANGER_SOLID yang berisi penuh — putih di atas merah di setiap tampilan, sedangkan label bahaya yang hanya dironai harus digelapkan
hingga nyaris hitam pada tema terang agar tetap terbaca. Nadanya disetel ulang pada setiap pemanggilan, karena jendelanya dipakai ulang.
if await dialogs.confirm("Delete this save?", "Slot 2 — Aria, level 12. This cannot be undone.",
"Delete", "Keep it", "", {}, true):
delete_save(2)
Tata letak tombol
action_layout | Fungsinya |
|---|---|
VERTICAL (default) | Tombol bertumpuk, selebar penuh. Aman untuk setiap bahasa — label bahasa Jerman atau Rusia yang panjang tidak pernah terjepit. |
HORIZONTAL | Satu baris, masing-masing separuh lebar. |
AUTO | Satu baris hanya bila kedua label muat di separuh kartu dalam satu baris; bertumpuk bila tidak. Diputuskan ulang saat bahasa berganti atau ukuran berubah. |
action_gap adalah jarak antartombol, body_gap jarak di atasnya — buat lebih lebar daripada
jarak antartombol agar pertanyaan dan pilihannya terbaca sebagai dua bagian. Untuk satu dialog saja, panggil
set_next_action_layout() sebelum membukanya. Satu-satunya tombol pada alert selalu selebar penuh.
Satu per satu
confirm() kedua selagi satu masih terbuka langsung mengembalikan false — dialog tidak pernah bertumpuk di atas dialog
secara tak sengaja. Nyalakan queue_when_busy dan ia akan antre menunggu gilirannya; alert() selalu menunggu.
queue_limit (8) membatasi panjang antrean, dan saat meluap permintaan tertua dijawab false.
pending() menghitung permintaan yang menunggu dan clear_pending() menjawab semuanya false.
choose() tidak pernah antre: ia mengembalikan -1 bila sebuah dialog sudah terbuka.
Ponsel dan desktop
choose() terbuka sebagai lembar dari bawah di Android dan iOS — tempat ibu jari berada — dan sebagai kartu di
tengah di desktop. Sebuah konfirmasi dibatasi pada max_width (420dp) dan diletakkan di tengah. Setel layer_index,
max_width, dan export lainnya sebelum add_child; semuanya diterapkan saat node masuk ke tree.
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 — jendela buatan Anda sendiri
Bila sebuah popup lebih dari sekadar pertanyaan — setelan, lembar karakter, barang untuk dibeli — bangun di atas
GoSurface. Area aman, keyboard, baris yang menempel, gulir, Kembali, fokus, dan pengubahan ukuran sudah beres.
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. Menyembunyikan atau membebaskan
jendela adalah tugas layar pemiliknya — hanya layar itu yang tahu apakah "tutup" berarti simpan, buang, atau bertanya dulu.
Tiga penempatan

CENTER — konfirmasi, setelan
BOTTOM — daftar, halaman pengelolaan
ANCHOR — di samping sebuah kontrol
GoDatePicker di dalam jendela CENTERANCHOR membutuhkan anchor_control. Kartunya ditaruh di kanan kontrol itu bila anchor_min_width muat,
kalau tidak di sisi yang lebih lebar, kalau tidak juga di dalam layar, dan terbuka ke atas bila ruang di atas lebih lapang. Ia mengikuti
anchor yang bergerak di setiap frame. anchor_width (320) dan anchor_max_height (520) menentukan ukurannya.
Seberapa besar jadinya
| Ukuran | Aturan | Diubah dengan |
|---|---|---|
| Ruang | Area aman, dikurangi keyboard, dikurangi margin layar (16dp, tidak pernah lebih dari 10% sisi pendek). | — |
| Lebar | 94% ruang dalam potret, 72% dalam lanskap, paling besar 480dp. | max_width · GoConfig.surface_width_ratio_* |
| Tinggi | Setinggi kontennya (fit_content), sampai 68% ruang, dibatasi 72%. Kartu di tengah yang tidak bisa diubah ukurannya boleh tumbuh hingga 94% agar tak perlu bergulir. | height_ratio · max_height_ratio · max_height |
| Kerapatan | Rapat bila compact disetel, layar lebih pendek dari 420dp (ponsel dimiringkan), atau kontennya tidak muat: padding lebih sedikit, jarak lebih kecil, judul lebih kecil. Ia mengukur keduanya dan memakai yang lebih lega yang masih muat — tanpa bergetar. | compact |
| Ubah ukuran | Dengan resizable, judulnya menjadi pegangan: seret di antara 30% dan batasnya. height_changed(ratio) melaporkan hasilnya. | resizable |
Rasio di atas batas dipotong kembali, dengan satu peringatan di build debug. Keyboard mendorong kartunya ke atas dan menggulir kolom yang terfokus ke dalam pandangan; area aman menjauhkannya dari notch dan bilah gestur di Android dan iOS.
Properti
| Properti | Default | Fungsinya |
|---|---|---|
placement | CENTER | CENTER, BOTTOM, atau ANCHOR |
dismiss_on_scrim | GoConfig.dismiss_on_scrim (false) | Ketukan pada selubung meminta tutup. Seretan yang dimulai di dalam kartu tidak. |
scrim_transparent | false | Biarkan game tetap terlihat — selubungnya tetap menangkap ketukan di luar. |
close_enabled | true | Menampilkan × dan membiarkan Escape serta Kembali meminta tutup. |
show_header · scroll_body · resizable | true · true · false | Baris header, body yang bergulir, pegangan seret. |
fit_content · compact | true · false | Ukuran mengikuti konten; mulai dalam keadaan rapat. |
fade_in | GoConfig.surface_fade_in (false) | Memunculkan kartu perlahan saat terbuka. Seketika di bawah reduce_motion. |
alpha | -1 (milik tema) | Opasitas muka kartu, sebagai rasio. Hanya mukanya yang memudar — teksnya tidak pernah. |
initial_focus | tidak ada | Kontrol yang difokuskan saat terbuka. |
add_child: scrim_transparent, show_header, resizable, dan
scroll_body diterapkan saat jendela masuk ke tree. dismiss_on_scrim, close_enabled,
fade_in, dan initial_focus dibaca langsung saat berjalan.
Sinyal dan pemanggilan
| Nama | Apa itu |
|---|---|
close_requested | ×, Escape, tombol Kembali Android, atau ketukan pada selubung — dan request_close(). Hanya dipancarkan oleh jendela teratas. |
back_requested · set_back(action) | Tombol kembali di header, untuk jendela yang punya beberapa halaman. Callable kosong menyembunyikannya. |
height_changed(ratio) | Setelah pegangannya diseret. |
is_top() · GoSurface.is_any_open() | Apakah ini jendela yang menerima Kembali — apakah ada jendela yang terbuka sama sekali. |
relayout() | Menata ulang sekarang juga. Mengubah properti ukuran sudah melakukannya untuk Anda. |
Lembar dan laci
Daftar yang butuh ruang naik dari bawah pada ponsel yang dipegang tegak — tempat ibu jari berada — dan masuk dari samping pada tablet atau desktop, tempat sebuah lembar akan menutupi game.

GoSheet
GoDrawer · LEFT
GoDrawer · RIGHTGoSheet — halaman-halaman dari bawah
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))
- Ia adalah
CanvasLayer(lapisan 10) yang memuatGoSurfaceBOTTOMyang bisa diubah ukurannya — jadi ia berada di atas HUD, dan pemain bisa menyeretnya lebih tinggi. open(title)memulai halaman baru: ia mengosongkan body, bilah alat, dan tombol kembali serta membebaskan apa yang ditambahkanadd_footer(). Panggil lagi untuk menampilkan halaman lain di lembar yang sama;set_back()menampilkan tombol kembali untuk jalan pulang.open_key()menerima kunci terjemahan.close()menyembunyikannya — tidak dibebaskan, jadiopen()berikutnya seketika.closeddanpage_changedmemberi tahu Anda kapan itu terjadi.height_ratio(0.6) adalah tinggi saat dibuka;max_height_ratiomenaikkan batasnya;dismissable(true) menutupnya saat selubung diketuk.
set_back() — hanya tombol kembali di layar
yang mundur satu halaman. Bila Kembali seharusnya mundur selangkah, tangani sendiri close_requested pada sheet.surface.
GoDrawer — dari samping
var drawer := GoDrawer.new()
drawer.side = GoDrawer.Side.LEFT
drawer.follow_text_direction = true # sisi awal: kiri, atau kanan dalam bahasa Arab
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")
- Lapisan 80. Lebarnya 42% layar (
width_ratio), di antaramin_width(320dp) danmax_width(420dp) — di ponsel ia menutupi sebagian besar layar, itulah sebabnya lembar lebih tepat di sana. - Panelnya mencapai tepi layar; hanya kontennya yang bergeser masuk dari area aman, sehingga sudut membulat tidak pernah memotong baris pertama.
LEFTberarti kiri layar bahkan dalam bahasa Arab. Nyalakanfollow_text_directionbila yang dimaksud adalah "sisi awal";effective_side()memberi tahu ke mana ia akhirnya pergi.open(title)mempertahankan body — isi sekali saja.set_title("")menyembunyikan header.motion_seconds(0.2) menggesernya masuk;reduce_motionmembuatnya seketika.
drawer.close() dari tombol pintas Anda sendiri — dan perhatikan bahwa GoSurface.is_any_open() tidak menghitung laci;
tanyakan drawer.is_open().
Kartu dan menu di samping sebuah kontrol
Apa yang baru saja ditekan pemain layak dijawab tepat di samping jarinya, bukan di tengah layar.

GoPopover
GoContextMenu
GoStyle.dropdown()
GoStyle.select()
GoComboboxGoPopover — kartu pada benda yang ditekan
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}))
Sebuah jendela ANCHOR dengan lapisan, anchor, dan pembongkarannya sudah terpasang — sepuluh baris yang ditulis setiap game
berulang-ulang. Satu per satu: membuka yang kedua menutup yang pertama, karena kartu yang bertumpuk mengubur layar dan tak seorang pun
bisa tahu mana milik slot yang mana. Selubungnya transparan — kartu yang dibuka untuk membandingkan perlengkapan tidak boleh menggelapkan perlengkapannya —
tetapi ia tetap menangkap ketukan pertama di luar, yang menutup kartunya dan tidak diteruskan.
| Opsi | Default | Fungsinya |
|---|---|---|
title | "" | Header dengan ×. Kosong berarti tanpa header. |
width · max_height | 320 · 520 | Ukuran kartunya. |
dismissable | true | Ketukan di luar menutupnya. |
compact · alpha · translate | false · -1 · false | Jarak yang rapat, opasitas muka, judul sebagai kunci terjemahan. |
layer | 95 | CanvasLayer tempat ia terbuka. |
GoPopover.close() dan GoPopover.is_open() bersifat statis. open() mengembalikan jendelanya — atau
null bila anchor tidak ada di tree, jadi periksa dulu sebelum Anda await shown.close_requested.
dismissable = false tanpa judul, tak ada apa pun di layar yang bisa menutupnya — hanya Escape, Kembali, atau pemanggilan Anda sendiri.
GoContextMenu — tekan lama dan klik kanan
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))
- Klik kanan langsung membukanya. Jari yang ditahan setengah detik (
HOLD_SECONDS) membukanya; bergerak lebih dari 12dp membatalkannya — jadi menggulir daftar tidak pernah memunculkan menu. - Sebuah item berupa
{text, action, icon, disabled, checked, separator, danger, translate}. BerikanCallablealih-alih array bila entrinya bergantung pada apa yang ditekan; ia dipanggil setiap kali menu terbuka. dangermenaruh "⚠ " di depan teks — menu milik engine hanya bisa mewarnai semua itemnya sekaligus.- Ini adalah
PopupMenumilik engine, didandani olehGoStyle.style_popup(). Ia tidak dihitung sebagai jendela yang terbuka.
⋯ yang terlihat
(open_at(), seperti di atas), atau ajarkan sekali lewat coach mark.
Dropdown, kotak pilihan, dan tombol terbelah
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"])
Ketiganya membuka menu popup milik engine: dropdown() adalah MenuButton yang menjalankan sebuah tindakan,
select() adalah OptionButton yang menyimpan sebuah nilai, GoSplitButton adalah tindakan utama ditambah menu pada
panahnya (chosen(index)). Menu sengaja dibiarkan buram sepenuhnya — menu yang ditampilkan di jendela OS-nya sendiri mengubah
piksel tembus pandang menjadi hitam.
GoCombobox — daftar yang bisa dicari
var friend := GoCombobox.make(friend_names, -1, "Find a friend")
friend.picked.connect(func(index: int) -> void: invite(friend_names[index]))
Saat ditekan, ia membuka daftar tertambat di lapisan 96 dengan selubung transparan. Mulai dari search_threshold (8) entri, sebuah
kolom pencarian muncul dan mengambil fokus; ia mencocokkan di bagian mana pun dari teks atau petunjuknya, tanpa membedakan huruf besar-kecil, dan hasil
kosong pun diberitahukan. list_width (0 = lebar tombolnya, minimal 180dp) menentukan lebar daftarnya.
Popup yang tidak pernah menghentikan game
Kabar yang bisa dibaca pemain sambil bermain. Tak satu pun memiliki selubung; ketukan di mana saja selain kartunya sendiri sampai ke game.

GoSnackbar
GoNotice
GoPromptCard
GoStyle.tooltip_node()GoSnackbar — pesan dengan Urungkan
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)
Kunci post() | Fungsinya |
|---|---|
text · title · args · translate | Pesannya, baris tebal opsional, {placeholders}, kunci terjemahan. |
tone · icon | Warna aksen (GoTheme.SUCCESS, WARNING…) dan sebuah ikon. |
actions · closable | Tombol — String atau {text, action} — dan sebuah ×. |
seconds | Berapa lama ia bertahan. Negatif: notice_duration_ms dari tema. 0: sampai ditutup — kalau begitu beri ia sebuah tombol. |
post() mengembalikan indeks tombol yang ditekan, atau -1 bila waktunya habis atau ditutup. Kiriman
mengantre (queue_limit 4, yang tertua dibuang dengan -1), dan teks yang sama yang dikirim lagi selagi tampil hanya mengisi ulang
pengatur waktunya. Ia berada di bawah (atau di atas, placement), di atas area aman dan keyboard, pada lapisan 90 — tetap terbaca
di atas laci. Dengan tap_to_dismiss (menyala) ketukan pada kartu tanpa tombol menutupnya; ketukan di luar kartu selalu
sampai ke game. show_text() dan show_key() adalah bentuk satu barisnya.
GoNotice — satu baris di 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)
Panel polos yang Anda tempatkan sendiri — di dalam GoHudAnchor, di sebuah sudut, di mana saja. Ia tidak mengambil input maupun fokus,
sehingga menekan menembusnya sampai ke tombol di bawahnya, dan pesan baru menggantikan yang lama. Beri ia lebar:
preferred_width(limit) mengembalikan lebar alami teks pendek dan membungkus teks panjang di dalam limit.
set_content() menampilkan kontrol apa saja sebagai ganti teks.
GoPromptCard — pertanyaan yang bisa menunggu
var spot := GoHudAnchor.new()
spot.spot = GoHudAnchor.Spot.TOP_CENTER
spot.reserve_space = false
spot.avoid_peers = true # turun ke bawah bilah darah alih-alih menutupinya
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)
- Ia mulai dalam keadaan tersembunyi — panggil
show(). Ia tidak punya pengatur waktu sendiri; tambahkan satu bila pertanyaannya bisa kedaluwarsa. - Tombol-tombolnya tidak menutupnya — tindakannya yang memutuskan. × (
set_closable(true)) memancarkanclosed. fit_width(width)menyetel lebar dan memperkirakan tingginya dari font, sehingga tidak ada yang ditata terhadapnya melompat satu frame kemudian.- Mukanya mengikuti
hud_alpha— ia bagian dari HUD, bukan sebuah jendela.
GoBanner dan tooltip
GoBanner.make("You're offline.", [{"text": "Retry", "action": reconnect}], GoIconSet.WARNING) berada di dalam
halaman itu sendiri, di atas konten, dan tidak pernah kedaluwarsa; sebuah tombol menutupnya kecuali ia punya "keep": true.
GoStyle.tooltip_node(text) adalah yang dikembalikan dari _make_custom_tooltip() — engine menggambar pelatnya
(TooltipPanel), gohud menggambar teksnya, dibungkus setelah 260dp. Tooltip itu untuk tetikus; jangan pernah menyembunyikan apa yang dibutuhkan pemain di baliknya.
Tur dan konsol

GoCoachMark
GoConsoleGoCoachMark — tur pada kontrol yang sungguhan
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."}])
- Cincin di sekeliling kontrol yang sungguhan dan kartu di sampingnya. Menekan sasarannya melanjutkan tur (sinyal
pressed-nya, atau"signal"pada langkah itu); Lanjut dan Lewati ada di kartu. Sasaran yang tersembunyi dilewati. - Kartunya menjauh dari tengah layar (
avoid_center_band), dari anchor HUD, dan darikeep_clear. - Selama ada
GoSurfaceyang terbuka, tur bersembunyi dan menunggu. Kembali atau Escape mengakhirinya denganfinished(false). - Ia tidak punya lapisan sendiri — tambahkan paling akhir, atau di lapisan di atas HUD.
GoConsole — cheat selama pengembangan
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()
Lapisan 200 — di atas segalanya, jadi Anda bisa men-debug di atas dialog — dan ia tetap berjalan saat tree dijeda. Sebuah palet menyarankan perintah selagi Anda mengetik; Atas dan Bawah menelusuri riwayat; Escape menutupnya. Tidak ada tombol bawaan: pasang tombol Anda sendiri.
debug_only (menyala) memblokirnya di build rilis — baik open() maupun run(). Perintah cheat di
tangan pemain mengakhiri ekonomi sebuah game pada hari pertama.
Lapisan, Kembali, dan input
Tiga aturan menentukan apa yang bisa disentuh pemain selagi sesuatu terbuka: apa yang ada di paling atas, siapa pemilik Kembali, dan siapa yang menerima ketukan.
Apa yang ada di paling atas
| Lapisan | Isinya | Disetel dengan |
|---|---|---|
| 5 | HUD Anda (pilihan Anda) | — |
| 10 | GoSheet | CanvasLayer.layer |
| ~50 | Jendela GoSurface buatan Anda, menu jeda | CanvasLayer milik Anda |
| 80 | GoDrawer | CanvasLayer.layer |
| 90 | GoSnackbar | layer_index |
| 95 | GoPopover | opsi "layer" |
| 96 | Daftar GoCombobox | — |
| 100 | GoDialogs | layer_index |
| 200 | GoConsole | layer_index |
Urutan ini disengaja: snackbar melaporkan apa yang baru terjadi, jadi ia harus terbaca di atas laci; popover milik apa yang baru ditekan, jadi ia berada di atasnya; dialog mengajukan pertanyaan dan menutupi keduanya; konsol menutupi segalanya, karena itulah yang Anda buka ketika semua yang lain sudah kacau.
Siapa pemilik Kembali
- Hanya jendela teratas yang menjawab. Di antara jendela yang terbuka, yang berada di lapisan tertinggi (lalu yang terbaru di tree)
menerima Escape, tombol batal gamepad (
ui_cancel), tombol Kembali Android, dan ketukan pada selubung. Jendela yang bertumpuk tertutup satu per satu, tidak pernah bersamaan. - Tombol Kembali Android ditangani satu frame kemudian, sehingga satu tekanan tidak pernah menutup dua jendela.
- Selama masih ada pemilik Kembali yang terbuka, tombol Kembali Android tidak keluar dari aplikasi (
GoBackPolicymenghitung pemiliknya dan memulihkanquit_on_go_backsetelah yang terakhir). Popup buatan Anda yang menerima Kembali sebaiknya memanggilGoBackPolicy.acquire()danrelease()— di_exit_treejuga. - Laci, tur coach mark, dan formulir mengalah selagi ada jendela yang terbuka — Kembali pergi ke jendela itu lebih dulu.
GoConfig.close_on_back(menyala) adalah sakelarnya untuk jendela-jendela itu.
Siapa yang menerima ketukan
- Sebuah jendela menutupi seluruh layar dan menghentikan input — selubung transparan juga. Tak ada apa pun di lapisan yang lebih rendah yang tertekan selagi ia terbuka; lapisan di atasnya (sebuah snackbar) tetap bisa ditekan.
- Roda tetikus dan gestur cubit juga berhenti di jendela itu: menggulir melewati ujung daftar tidak pernah menggulir game.
- Input permainan yang tidak melewati kontrol —
_unhandled_inputuntuk gerakan, seretan kamera — sebaiknya berhenti sejenak:if GoSurface.is_any_open(): return. Itu mencakup dialog, lembar, popover, dan combobox; untuk laci tanyakanis_open()secara terpisah. - Snackbar, pemberitahuan, kartu ajakan, dan coach mark hanya menerima input di kartunya sendiri; di tempat lain, game yang menerimanya.
Fokus
Jendela yang dibuka dengan pointer tidak memfokuskan apa pun — tidak ada cincin fokus yang berkedip saat disentuh. Bila dibuka dari papan ketik atau gamepad, tombol tutup
(atau initial_focus) mengambil fokus. Fokus tetap di dalam jendela selama ia terbuka dan kembali ke kontrol yang tadi
memegangnya saat jendela ditutup. Dialog selalu memfokuskan OK.
Menjeda game
Menjeda tree juga menjeda popup — hanya konsol yang tetap bekerja. Untuk menu jeda, beri lapisannya
process_mode = PROCESS_MODE_ALWAYS; maka jendela, tombol-tombolnya, dan Kembali tetap berjalan selagi game berhenti.
Popup yang sama di setiap tampilan
Konfirmasi dari bagian atas halaman ini, di atas game yang sama, dengan hanya presetnya yang diganti. Kodenya identik — tema, skin, dan ikon mengerjakan sisanya.

default_dark
default_light
scifi_dark
scifi_light
medieval_dark
medieval_light
material_light Baru
material_dark Baru
kids_light Baru
kids_dark Baru
comic_light Baru
comic_dark Baru
arcade_light Baru
arcade_dark BaruApa yang diubah setiap tampilan
| Tampilan | Jendelanya | Kepala dan tombolnya |
|---|---|---|
| Default | Membulat (18dp), bayangan lembut, 80% buram di atas game | Judul dan × polos; tombol primer terangkat lalu tenggelam |
| Sci-fi | Sudut terpotong dengan tepi neon dan pendar, tepinya diwarnai aksen | Penanda fokus berbentuk kurung |
| Abad pertengahan | Bingkai tempaan — besi dan kulit, atau perkamen — dengan paku keling dan ornamen sudut | Judul dalam Cinzel |
| Material 3 | Sudut 28dp, padding 24dp, buram sepenuhnya | Judul 24sp dalam Roboto; tombol pil dengan pelat 40dp di dalam target 48dp |
| Anak-anak | Kartu permen jeli dengan bayangan lembut, buram sepenuhnya | Pita judul cerah (mint di malam hari), tombol tutup permen bulat, tombol yang memipih saat ditekan |
| Komik | Garis tepi tinta tebal dan bayangan tegas, buram sepenuhnya | Keterangan judul kuning, tombol tutup bulat bertinta, tombol yang bayangannya hilang saat ditekan |
| Arcade | Papan tebal — bingkai berwarna di sekeliling ceruk pucat — buram sepenuhnya | Spanduk judul emas dengan judul putih bergaris tepi tinta, tombol tutup merah yang bundar, tombol bercat yang melompat saat ditekan |
Mendandani popup dari skin
Skin menentukan bagian-bagian yang tak terjangkau Theme. Hook berikut adalah yang dipanggil popup — timpa di subkelas
GoSkin milik Anda; secara default semuanya tidak melakukan apa-apa.
| Hook | Yang didandaninya |
|---|---|
title_plate_box() · title_plate_ink() · title_plate_min_size() | Pelat di balik judul jendela. Judulnya memusat di atasnya dan mengecil, sampai ukuran minimum (15), agar tetap satu baris. |
dress_close_button(button) | Tombol × jendela — kids menjadikannya permen bulat, comic cakram bertinta, arcade tombol merah yang bundar. |
dress_title(label) | Label judul jendela — arcade memberi judul putihnya garis tepi tinta. |
press_feedback(control) | Berjalan begitu jari menyentuh tombol buatan gohud — kids membuatnya memipih, arcade membuatnya melompat. |
floating_box() · notice_box() · drawer_box() · banner_box() · overlay_box() | Muka kartu ajakan dan kartu coach, snackbar dan pemberitahuan, laci, banner, konsol. |
coach_ring_box() · draw_coach_pointer() | Cincin dan penunjuk tur. |
Seberapa tembus pandang
Setiap jenis popup mengikuti opasitasnya sendiri, sehingga kartu HUD bisa tetap ringan sementara dialog tetap pejal: jendela, lembar, dialog,
popover, dan combobox mengikuti panel_alpha; laci dan kartu coach card_alpha; kartu ajakan dan
konsol hud_alpha; snackbar dan pemberitahuan notice_alpha; menu popup_alpha. Material dan kids
membuat semuanya buram; comic juga, kecuali kartu ajakan dan konsol yang 92%, dan arcade, kecuali keduanya yang 94%. Timpa satu jenis dengan GoConfig.container_alpha_overrides, semuanya dengan
container_alpha (sebuah rasio — 0.95), atau satu jendela dengan alpha-nya. Hanya mukanya yang memudar; teks
tidak pernah tembus pandang. Opasitas secara rinci →
Setelan yang membentuk setiap popup
Kolom-kolom GoConfig (GoUi.config). Beberapa disalin saat sebuah jendela dibuat, jadi setel
sebelum membangun UI — atau panggil GoUi.refresh() setelah mengubahnya.
| Kolom | Default | Fungsinya |
|---|---|---|
surface_max_width · surface_max_height | 480 · 700 | Ukuran terbesar sebuah jendela. |
surface_height_ratio · surface_max_height_ratio | 0.68 · 0.72 | Tinggi yang biasa dan batasnya (juga batas seretan). |
surface_fit_max_height_ratio | 0.94 | Seberapa besar kartu di tengah yang mengikuti konten boleh tumbuh sebelum bergulir. |
surface_width_ratio_portrait · …_landscape | 0.94 · 0.72 | Lebar sebagai bagian dari ruang. |
dismiss_on_scrim | false | Ketukan pada selubung menutup jendela dan dialog. Disalin saat jendela dibuat. |
surface_fade_in · fade_seconds | false · 0.14 | Memunculkan jendela perlahan, dan seberapa cepat. |
close_on_back | true | Escape, ui_cancel, dan tombol Kembali Android menutup jendela teratas. |
close_button_visual | 36 | Seberapa besar × terlihat — target sentuhnya tetap 48dp. |
suppress_pointer_focus_ring | true | Tanpa cincin fokus bila jendela dibuka dengan sentuhan atau tetikus. |
container_alpha · container_alpha_overrides | -1 · {} | Opasitas setiap muka, atau per jenis (GoTheme.BOX_*). |
reduce_motion | false | Tanpa pudar, geser, denyut, atau pipih. |
min_touch_size | 48 | Tinggi tombol kartu ajakan dan coach mark. |
respect_safe_area | true | Menjauhkan jendela dari notch dan bilah gestur. |
text_keys · text_overrides | — | Kata-kata milik kit sendiri: tutup, kembali, konfirmasi, batal, lanjut, selesai, lewati, cari, kosong… |
sound_cues · haptik | — | Apa yang dimainkan GoFeedback saat dibuka, ditutup, dikonfirmasi, dibatalkan, dan diketuk. |
Resep
Salin, tempel, ganti kata-katanya. Setiap pemanggilan di sini diperiksa terhadap kode sumbernya.
Pembelian yang menyebutkan harganya
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)
Jendela setelan dengan tombol Simpan yang menempel
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)
Formulir yang mengatakan apa yang salah
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())
Tanggal di dalam lembar
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 jeda
func pause() -> void:
get_tree().paused = true
var layer := CanvasLayer.new()
layer.layer = 50
layer.process_mode = Node.PROCESS_MODE_ALWAYS # tetap berjalan selagi game dijeda
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)
Gameplay yang menunggu popup
func _unhandled_input(event: InputEvent) -> void:
if GoSurface.is_any_open() or drawer.is_open():
return
handle_gameplay(event)
Jebakan
GoSurfacetidak pernah membebaskan dirinya sendiri. Sambungkanclose_requested, atau × tidak melakukan apa-apa.- Opsi yang disetel setelah
add_child—scrim_transparent,show_header,resizable,scroll_body, sertalayer_indexdanmax_widthmilikGoDialogs— tidak diterapkan. confirm()kedua langsung mengembalikanfalse. Nyalakanqueue_when_busybila dua pertanyaan bisa bertemu.- Enter mengonfirmasi. OK memegang fokus, pada dialog destruktif juga.
- Kembali pada lembar menutup lembarnya, bukan subhalamannya.
- Escape tidak menutup laci, dan
is_any_open()tidak melihatnya. - Popover atau daftar combobox memblokir game sampai ditutup, bahkan dengan selubung transparan — dan popover dengan
dismissable = falsetanpa judul tidak punya apa pun di layar yang bisa menutupnya. - Kartu ajakan mulai dalam keadaan tersembunyi dan tidak punya batas waktu.
- Snackbar dengan
seconds: 0tanpa tombol tidak pernah pergi. Dan secara default ia menangkap ketukan pada kartunya. - Tekan lama yang tak diketahui siapa pun adalah fitur yang tak dipakai siapa pun. Tampilkan juga
⋯. - Tree yang dijeda menjeda popup Anda. Pakai
PROCESS_MODE_ALWAYSpada lapisannya. - Pemberitahuan tanpa lebar menyusut ke bentuk tersempitnya — pakai
preferred_width(). - Jangan pernah bertanya lewat snackbar, jangan pernah sekadar memberi kabar lewat dialog. Pertanyaan lenyap bila diabaikan; kabar tidak semestinya menghentikan game.