Episode ini fokus pada antarmuka: hirarki Control nodes, container dan layout system, beragam widget seperti button, label, slider, dan menu, teknik responsive UI dengan anchoring, serta menghubungkan sinyal UI ke logika game yang sebenarnya.

Dua episode terakhir kalian membangun dunia — pertama 2D, lalu 3D. Tapi pemain tidak hanya butuh dunia; mereka butuh cara berkomunikasi dengannya. Di episode 6 kita sempat menyinggung CanvasLayer sebagai overlay. Episode 8 ini adalah pembahasan penuh tentang antarmuka: UI & HUD. Di sini kalian belajar menyusun layout yang rapi, membuat menu yang fungsional, dan menyambungkan semua widget ke logika game.
Roadmap episode ini: kita mulai dari Control node sebagai dasar segala UI, mempelajari container dan layout system, mengenal widget-widget utama seperti Button, Label, Slider, dan PanelContainer, lalu membuat UI responsive dengan anchoring, dan menutupnya dengan menghubungkan sinyal UI ke interaksi logika game.
Semua elemen antarmuka di Godot menurun dari node Control. Control punya sistem koordinat sendiri yang berbeda dari dunia: position dihitung dari pojok kiri-atas, dan ukuran diatur lewat properti size. Ini mengapa UI tidak ikut berubah saat kamera bergeser — ia hidup di ruang layar, bukan di ruang dunia.
Ada tiga properti kunci pada setiap Control: position (pojok kiri-atas), size (lebar dan tinggi), dan anchor. Untuk menempatkan elemen dengan presisi, letakkan semua UI di dalam CanvasLayer atau langsung sebagai child scene Control root. Godot juga menyediakan panel Layout di toolbar editor yang mengatur anchor dan offset secara visual.
extends Control
func _ready() -> void:
position = Vector2(20, 20)
size = Vector2(200, 50)
print("rect global: %s" % get_global_rect())Jangan tergoda untuk menaruh Label atau Button langsung di scene world — tanpa Control parent yang menempel layar, posisinya akan bergeser-geser tidak terkendali. Selalu bungkus UI di CanvasLayer atau Control root.
Menaruh widget satu per satu dengan koordinat manual itu menyiksa — dan hancur begitu resolusi layar berubah. Solusinya adalah container: node yang mengatur posisi dan ukuran child-nya secara otomatis. Cukup buat VBoxContainer atau HBoxContainer, masukkan beberapa Button, dan Godot menyusunnya rapi berurutan tanpa kalian menyentuh satu angka pun.
Container populer yang wajib kalian tahu:
VBoxContainer — menyusun child vertikal dari atas ke bawah.HBoxContainer — menyusun child horizontal dari kiri ke kanan.GridContainer — menyusun child dalam grid sesuai kolom yang ditentukan.MarginContainer — menambah jarak di sekeliling isinya.CenterContainer — memusatkan child di tengah area.Container menghormati properti size_flags_horizontal dan size_flags_vertical pada tiap child. Set EXPAND agar child mengisi ruang ekstra, atau SHRINK_CENTER agar tetap di tengah. Contoh menu sederhana:
extends VBoxContainer
func _ready() -> void:
add_button("Start Game")
add_button("Settings")
add_button("Quit")
func add_button(text: String) -> void:
var button := Button.new()
button.text = text
add_child(button)Hasilnya tiga tombol tersusun rapi vertikal dan otomatis menyesuaikan diri. Container adalah kunci produktivitas UI di Godot — gunakan berlapis: MarginContainer > VBoxContainer > barisan HBoxContainer untuk layout yang kompleks.
Godot menyediakan widget siap pakai untuk hampir semua kebutuhan UI:
Label — teks statis atau dinamis untuk skor dan pesan.Button — aksi yang bisa diklik; punya varian CheckButton, ToggleButton, dan OptionButton.LineEdit — input teks satu baris untuk nama pemain.HSlider dan VSlider — kontrol nilai kontinu, pas untuk volume dan kecepatan.ProgressBar — menampilkan nilai dalam bentuk batang.PanelContainer / Panel — wadah visual dengan background untuk menampung elemen lain.PopupMenu — dropdown menu kontekstual.Menata sebuah halaman settings biasanya menyatukan beberapa widget tersebut dalam container. Misalnya baris volume terdiri dari Label ("Music"), HSlider, dan Label persentase — semua di dalam satu HBoxContainer. Untuk menu utama, bungkus semua tombol dalam CenterContainer lalu beri PanelContainer sebagai latar agar terlihat seperti menu sungguhan.
Info
Godot memiliki tema global untuk UI. Atur Theme di project settings agar semua Button, Label, dan Panel memakai gaya konsisten tanpa styling satu per satu. Untuk polish cepat, atur StyleBoxFlat pada panel: beri warna background, corner radius, dan border.
Layar game tidak selalu sama: dari ponsel portrait sampai monitor ultrawide. Agar UI tetap benar di semua kondisi, kalian pakai anchoring. Anchor menentukan bagian mana dari area parent yang menjadi acuan posisi. Empat pojok anchor: kiri-atas (0,0), kanan-bawah (1,1).
Beberapa pola anchor yang umum:
(0,0) sampai (1,1); elemen meregang mengikuti ukuran layar. Dipakai untuk background dan container utama.Anchor bekerja berpasangan dengan offset (jarak dari anchor) dan grow_direction (arah berkembang saat ukuran parent berubah). Untuk panel popup yang selalu di tengah berapa pun resolusinya, cukup atur anchor center dan biarkan offset-nya otomatis. Contoh menempatkan tombol di pojok kanan-bawah:
extends Button
func _ready() -> void:
anchors_preset = Control.PRESET_BOTTOM_RIGHT
offset_left = -200.0
offset_top = -50.0
offset_right = -20.0
offset_bottom = -20.0Perhatikan: dengan anchor bottom-right, offset bernilai negatif berarti "mundur dari tepi". Pola ini membuat tombol selalu menempel pojok kanan-bawah di layar berapa pun ukurannya.
UI tanpa logika hanyalah gambar. Jembatan antara keduanya adalah sinyal. Semua widget mengeluarkan sinyal: Button memancarkan pressed, HSlider memancarkan value_changed, LineEdit memancarkan text_submitted. Kalian bisa menyambungkannya di editor lewat panel Node, atau secara programatik dengan connect().
Cara paling idiomatis di Godot 4 adalah lewat anotasi @onready dan referensi node, lalu connect() di _ready():
extends Control
@onready var start_button: Button = %StartButton
@onready var volume_slider: HSlider = %VolumeSlider
func _ready() -> void:
start_button.pressed.connect(_on_start_pressed)
volume_slider.value_changed.connect(_on_volume_changed)
func _on_start_pressed() -> void:
get_tree().change_scene_to_file("res://scenes/game.tscn")
func _on_volume_changed(value: float) -> void:
AudioServer.set_bus_volume_db(AudioServer.get_bus_index("Music"), value)Perhatikan anotasi %StartButton — ini adalah unique name yang dipakai Godot 4 agar referensi node tidak putus walau hierarki berubah. Sinyal UI bekerja persis seperti sinyal yang kalian buat sendiri di episode 5: emit dari widget, terima di script. Inilah cara membuat UI berbicara dengan logika game.
Sinyal yang terhubung adalah setengah jalan; separuh lainnya adalah logika yang menjalankan konsekuensinya. Untuk HUD, pola yang umum adalah menyimpan referensi ke node game dan memperbarui Label setiap kali nilai berubah. Contoh: counter skor yang bertambah saat koin diambil.
extends Control
@onready var score_label: Label = %ScoreLabel
var score := 0
func add_score(points: int) -> void:
score += points
score_label.text = "Skor: %d" % scoreSaat Area2D koin terdeteksi (pola dari episode 6), panggil get_node("../HUD").add_score(10) atau lebih baik lagi lewat sinyal kustom coin_collected yang dikirim HUD. Dengan cara ini HUD tidak perlu tahu detail deteksi koin — ia hanya mendengarkan dan memperbarui tampilan. Pemisahan inilah esensi arsitektur UI yang sehat.
Satu pola lagi yang berguna: paused menubar. Tombol pause di pojok layar memanggil get_tree().paused = true lalu menampilkan CanvasLayer berisi menu. Logikanya tetap UI sederhana — satu tombol mengubah status tree, satu panel muncul. Kita akan membedah pause menu secara penuh di episode 9 bersama state management.
Episode 8 membekali kalian dengan seluruh toolkit antarmuka: Control node sebagai dasar, container untuk layout otomatis, widget-widget standar seperti Button, Label, dan Slider, anchoring untuk UI yang responsive, serta sambungan sinyal yang menghubungkan UI ke logika game.
Inti yang harus dibawa pulang:
Control dan hidup di ruang layar, terpisah dari dunia game.pressed, value_changed) dan pola %UniqueName.Di episode 9 kalian masuk ke urusan yang lebih serius: Game State & Data Persistence. Kita akan membangun autoload singleton untuk game state, menyimpan dan memuat data dengan JSON serta ConfigFile, merancang scene transition dan state machine, sampai membuat pause menu dan settings yang benar-benar tersimpan. Sampai jumpa di dunia state!