Proyek referensi Tanaman

*Konten ini diterjemahkan menggunakan AI (Beta) dan mungkin mengandung kesalahan. Untuk melihat halaman ini dalam bahasa Inggris, klik di sini.

Tanaman adalah game referensi di mana pemain menanam dan menyiram biji, sehingga mereka dapat memanen dan menjual tanaman yang dihasilkan.

Spanduk proyek Tanaman

Proyek ini berfokus pada kasus penggunaan umum yang mungkin Anda temui saat mengembangkan game di Roblox. Di mana pun memungkinkan, Anda akan menemukan catatan tentang tradeoff, kompromi, dan alasan dari berbagai pilihan implementasi, sehingga Anda dapat membuat keputusan terbaik untuk game Anda sendiri.

Dapatkan file

  1. Navigasikan ke halaman game Tanaman.
  2. Klik tombol dan Edit di Studio.

Kasus penggunaan

Tanaman mencakup kasus penggunaan berikut:

  • Persistensi data sesi dan data pemain
  • Manajemen tampilan UI
  • Jaringan klien-server
  • Pengalaman Pengguna Pertama Kali (FTUE)
  • Pembelian mata uang keras dan lunak

Selain itu, proyek ini menyelesaikan seperangkat masalah yang lebih sempit yang berlaku untuk banyak game, termasuk:

  • Kustomisasi area di tempat yang terkait dengan pemain
  • Mengelola kecepatan gerak karakter pemain
  • Membuat objek yang mengikuti karakter
  • Mendeteksi bagian mana dari dunia yang sedang dijelajahi karakter

Perhatikan bahwa ada beberapa kasus penggunaan dalam game ini yang terlalu kecil, terlalu niche, atau tidak menunjukkan solusi untuk tantangan desain yang menarik; ini tidak dicakup.

Struktur proyek

Keputusan pertama saat membuat game adalah memutuskan bagaimana cara menyusun proyek, yang terutama mencakup di mana menempatkan instance tertentu dalam model data dan bagaimana mengorganisir serta menyusun titik masuk untuk kode klien dan server.

Model data

Tabel berikut menjelaskan layanan kontainer mana dalam model data yang digunakan untuk menempatkan instance.

LayananJenis instance
Workspace

Berisi model statis yang mewakili dunia 3D, khususnya bagian dunia yang tidak dimiliki oleh pemain mana pun. Anda tidak perlu membuat, memodifikasi, atau menghancurkan instance ini secara dinamis saat runtime, jadi tidak masalah jika dibiarkan di sini.

Juga terdapat Folder kosong, di mana model pertanian pemain akan ditambahkan saat runtime.

Lighting

Efek atmosfer dan pencahayaan.

ReplicatedFirst

Berisi subset terkecil dari instance yang diperlukan untuk menampilkan layar pemuatan dan menginisialisasi game. Semakin banyak instance yang ditempatkan di ReplicatedFirst, semakin lama waktu tunggu untuk mereplikasi sebelum kode di ReplicatedFirst dapat dijalankan.

  • Di folder Instances terdapat GUI layar pemuatan.
  • Di folder Source terdapat kode layar pemuatan dan kode yang diperlukan untuk menunggu sisa game dimuat. start LocalScript adalah titik masuk untuk semua kode sisi klien dalam proyek.
ReplicatedStorage

Berfungsi sebagai kontainer penyimpanan untuk semua instance yang memerlukan akses di klien dan server.

  • Di folder Dependencies terdapat beberapa pustaka pihak ketiga yang digunakan oleh proyek.
  • Di folder Instances terdapat berbagai instance prefabrikasi.
  • Di folder Source terdapat semua kode tidak yang diperlukan untuk proses pemuatan yang perlu diakses dari klien dan server.
ServerScriptService

Berisi Script yang berfungsi sebagai titik masuk untuk semua kode sisi server dalam proyek.

ServerStorage

Berfungsi sebagai kontainer penyimpanan untuk semua instance yang tidak perlu direplikasi ke klien.

  • Di folder Instances terdapat model template Farm. Salinan ini ditempatkan di Workspace saat pemain bergabung dengan game, di mana ia akan direplikasi ke semua pemain.
  • Di folder Source terdapat semua kode yang eksklusif untuk server.
SoundService

Berisi objek Sound yang digunakan untuk efek suara dalam game. Di bawah SoundService, objek Sound ini tidak memiliki posisi dan tidak disimulasikan dalam ruang 3D.

Titik masuk

Sebagian besar proyek mengorganisir kode di dalam ModuleScripts yang dapat digunakan kembali dan dapat diimpor di seluruh basis kode. ModuleScripts dapat digunakan kembali tetapi tidak dieksekusi sendiri; mereka perlu diimpor oleh Script atau LocalScript. Banyak proyek Roblox akan memiliki sejumlah besar objek Script dan LocalScript, masing-masing berkaitan dengan perilaku atau sistem tertentu dalam game, menciptakan beberapa titik masuk.

Untuk mikrogame Tanaman, pendekatan yang berbeda diterapkan melalui satu LocalScript yang merupakan titik masuk untuk semua kode klien, dan satu Script yang merupakan titik masuk untuk semua kode server. Pendekatan yang benar untuk proyek Anda tergantung pada kebutuhan Anda, tetapi satu titik masuk memberikan kontrol yang lebih besar atas urutan di mana sistem dieksekusi.

Daftar berikut menggambarkan tradeoff dari kedua pendekatan:

  • Satu Script dan satu LocalScript mencakup kode server dan klien masing-masing.
  • Kontrol yang lebih besar atas urutan di mana berbagai sistem dimulai karena semua kode diinisialisasi dari satu skrip.
  • Dapat melewatkan objek dengan referensi antara sistem.

Arsitektur sistem tingkat tinggi

Sistem tingkat atas dalam proyek dijelaskan di bawah ini. Beberapa sistem ini secara substansial lebih kompleks daripada yang lain, dan dalam banyak kasus fungsionalitas mereka diabstraksikan melalui hierarki kelas lain.

Diagram arsitektur sistem proyek Tanaman

Setiap sistem ini adalah "singleton," di mana ia adalah kelas yang tidak dapat diinstansiasi yang diinisialisasi oleh skrip start klien atau server yang relevan. Anda dapat membaca lebih lanjut tentang pola singleton di bagian selanjutnya dari panduan ini.

Server

Sistem berikut terkait dengan server.

SistemDeskripsi
Jaringan
  • Membuat semua instance RemoteEvent dan RemoteFunction.
  • Mengekspos metode untuk mengirim dan mendengarkan pesan dari klien.
  • Validasi tipe untuk argumen yang diterima dari klien saat runtime.
PlayerDataServer
  • Menyimpan dan memuat data pemain yang persisten menggunakan DataStoreService.
  • Menyimpan data pemain dalam memori dan mereplikasi mutasi ke klien.
  • Mengekspos sinyal dan metode untuk berlangganan, menanyakan, dan memperbarui data pemain.
Pasar
  • Menangani transaksi mata uang lunak dari klien.
  • Mengekspos metode untuk menjual tanaman yang dipanen.
CollisionGroupManager
  • Menetapkan model karakter pemain ke grup tabrakan.
  • Mengonfigurasi grup tabrakan sehingga karakter pemain tidak dapat bertabrakan dengan gerobak tanaman.
FarmManagerServer
  • Membuat ulang model pertanian pemain dari data pemain mereka saat mereka bergabung dengan game.
  • Menghapus model pertanian saat pemain keluar.
  • Memperbarui data pemain saat pertanian pemain diubah.
  • Mengekspos metode untuk mengakses kelas Farm yang terkait dengan pemain tertentu.
PlayerObjectsContainer
  • Membuat berbagai objek yang terkait dengan masa hidup pemain dan menyediakan metode untuk mengambilnya.
TagPlayers
FtueManagerServer
  • Selama FTUE, mengeksekusi setiap tahap dan menunggu hingga selesai.
CharacterSpawner
  • Menghidupkan kembali karakter saat mereka mati. Perhatikan bahwa Players.CharacterAutoLoads telah dinonaktifkan sehingga pemunculan ditunda hingga data pemain dimuat.

Klien

Sistem berikut terkait dengan klien.

SistemDeskripsi
Jaringan
  • Menunggu server untuk membuat semua instance RemoteEvent dan RemoteFunction.
  • Mengekspos metode untuk mengirim dan mendengarkan pesan ke dan dari server.
  • Menegakkan validasi tipe parameter saat runtime.
  • Menjalankan pcall() pada fungsi jarak jauh.
PlayerDataClient
  • Menyimpan data pemain lokal dalam memori.
  • Mengekspos metode dan sinyal untuk menanyakan dan berlangganan pada perubahan data pemain.
MarketClient
  • Mengekspos metode untuk meminta server membeli item untuk mata uang lunak.
LocalWalkJumpManager
  • Mengekspos metode untuk memodifikasi WalkSpeed atau JumpHeight dari karakter melalui pengali untuk menghindari konflik saat memodifikasi nilai ini dari beberapa tempat.
FarmManagerClient
  • Mendengarkan tag CollectionService tertentu yang diterapkan pada instance dan membuat "komponen" yang menambahkan perilaku pada instance ini. "Komponen" mengacu pada kelas yang dibuat saat tag CollectionService ditambahkan ke instance dan dihancurkan saat dihapus; ini digunakan untuk prompt CTA di pertanian dan berbagai kelas yang menginformasikan status pertanian kepada pemain.
UISetup
  • Menginisialisasi semua lapisan UI.
  • Mengonfigurasi lapisan tertentu agar hanya terlihat di bagian fisik dunia.
  • Menghubungkan efek kamera khusus untuk saat menu diaktifkan.
FtueManagerClient
  • Mengonfigurasi tahap FTUE di klien.
CharacterSprint
  • Menggunakan LocalWalkJumpManager untuk meningkatkan WalkSpeed saat karakter pemain berada di luar pertanian mereka.

Komunikasi klien-server

Sebagian besar game Roblox melibatkan beberapa elemen komunikasi antara klien dan server. Ini dapat mencakup klien yang meminta server untuk melakukan tindakan tertentu dan server yang mereplikasi pembaruan ke klien.

Dalam proyek ini, komunikasi klien-server dijaga agar tetap umum mungkin dengan membatasi penggunaan objek RemoteEvent dan RemoteFunction untuk mengurangi jumlah aturan khusus yang perlu dilacak. Proyek ini menggunakan metode berikut, dalam urutan preferensi:

Replikasi melalui sistem data pemain

Sistem data pemain memungkinkan data untuk dikaitkan dengan pemain yang bertahan antara sesi penyimpanan. Sistem ini menyediakan replikasi dari klien ke server dan seperangkat API yang dapat digunakan untuk menanyakan data dan berlangganan pada perubahan, menjadikannya ideal untuk mereplikasi perubahan status pemain dari server ke klien.

Sebagai contoh, daripada memicu UpdateCoins RemoteEvent untuk memberitahu klien berapa banyak koin yang dimilikinya, Anda dapat memanggil yang berikut dan membiarkan klien berlangganan melalui event PlayerDataClient.updated.

PlayerDataServer.setValue(player, "coins", 5)

Tentu saja, ini hanya berguna untuk replikasi dari server ke klien dan untuk nilai yang ingin Anda pertahankan antara sesi, tetapi ini berlaku untuk sejumlah kasus yang mengejutkan dalam proyek, termasuk:

  • Tahap FTUE saat ini
  • Inventaris pemain
  • Jumlah koin yang dimiliki pemain
  • Status pertanian pemain

Replikasi melalui atribut

Dalam situasi di mana server perlu mereplikasi nilai khusus ke klien yang spesifik untuk Instance tertentu, Anda dapat menggunakan atribut. Roblox secara otomatis mereplikasi nilai atribut, jadi Anda tidak perlu mempertahankan jalur kode apa pun untuk mereplikasi status yang terkait dengan objek. Keuntungan lain adalah bahwa replikasi ini terjadi bersamaan dengan instance itu sendiri.

Ini sangat berguna untuk instance yang dibuat saat runtime, karena atribut yang diatur pada instance baru sebelum diparent ke model data akan mereplikasi secara atomik dengan instance itu sendiri. Ini menghindari kebutuhan untuk menulis kode untuk "menunggu" data tambahan direplikasi melalui RemoteEvent atau StringValue.

Anda juga dapat langsung membaca atribut dari model data, baik dari klien atau server, dengan metode GetAttribute() dan berlangganan pada perubahan dengan metode GetAttributeChangedSignal(). Dalam proyek Tanaman, pendekatan ini digunakan untuk, antara lain, mereplikasi status saat ini dari tanaman ke klien.

Replikasi melalui tag

CollectionService memungkinkan Anda menerapkan tag string ke Instance. Ini berguna untuk mengkategorikan instance dan mereplikasi kategorisasi itu ke klien.

Sebagai contoh, tag CanPlant diterapkan di server untuk menandakan kepada klien bahwa pot tertentu dapat menerima tanaman.

Mengirim pesan langsung melalui modul jaringan

Untuk situasi di mana tidak ada opsi sebelumnya yang berlaku, Anda dapat menggunakan panggilan jaringan khusus melalui modul Jaringan. Ini adalah satu-satunya opsi dalam proyek yang memungkinkan komunikasi dari klien ke server dan oleh karena itu paling berguna untuk mentransmisikan permintaan klien dan menerima respons dari server.

Tanaman menggunakan panggilan jaringan langsung untuk berbagai permintaan klien, termasuk:

  • Menyiram tanaman
  • Menanam biji
  • Membeli item

Kekurangan dari pendekatan ini adalah bahwa setiap pesan individu memerlukan beberapa konfigurasi khusus yang dapat meningkatkan kompleksitas proyek, meskipun ini telah dihindari di mana pun memungkinkan, terutama untuk komunikasi dari server ke klien.

Kelas dan singleton

Kelas dalam proyek Tanaman, seperti instance di Roblox, dapat dibuat dan dihancurkan. Sintaks kelasnya terinspirasi oleh pendekatan idiomatik Lua untuk pemrograman berorientasi objek dengan sejumlah perubahan untuk mendukung dukungan pemeriksaan tipe ketat.

Instansiasi

Banyak kelas dalam proyek ini terkait dengan satu atau lebih Instances. Objek dari kelas tertentu dibuat menggunakan metode new() yang konsisten dengan cara instance dibuat di Roblox menggunakan Instance.new().

Pola ini umumnya digunakan untuk objek di mana kelas memiliki representasi fisik dalam model data, dan kelas memperluas fungsionalitasnya. Contoh yang baik adalah BeamBetween yang membuat objek Beam antara dua objek Attachment yang diberikan dan menjaga agar lampiran tersebut terorientasi sehingga sinar selalu menghadap ke atas. Instance ini dapat diklon dari versi prefabrikasi di ReplicatedStorage atau diteruskan ke new() sebagai argumen dan disimpan di dalam objek di bawah self.

Instance yang sesuai

Seperti yang disebutkan di atas, banyak kelas dalam proyek ini memiliki representasi model data, sebuah instance yang sesuai dengan kelas dan dimanipulasi olehnya.

Alih-alih membuat instance ini saat objek kelas diinstansiasi, kode umumnya memilih untuk Clone() versi prefabrikasi dari Instance yang disimpan di bawah ReplicatedStorage atau ServerStorage. Meskipun mungkin untuk menyerialisasi properti dari instance ini dan membuatnya dari awal dalam fungsi new() kelas, melakukannya akan membuat pengeditan objek menjadi sangat merepotkan dan membuatnya lebih sulit bagi pembaca untuk memahami. Selain itu, mengkloning instance umumnya merupakan operasi yang lebih cepat daripada membuat instance baru dan menyesuaikan propertinya saat runtime.

Komposisi

Meskipun pewarisan dimungkinkan di Luau menggunakan metatables, proyek ini memilih untuk membiarkan kelas memperluas satu sama lain melalui komposisi. Saat menggabungkan kelas melalui komposisi, objek "anak" diinstansiasi dalam metode new() kelas dan disertakan sebagai anggota di bawah self.

Sebagai contoh dari ini dalam tindakan, lihat kelas CloseButton yang membungkus kelas Button.

Pembersihan

Mirip dengan bagaimana Instance dapat dihancurkan dengan metode Destroy(), kelas yang dapat diinstansiasi juga dapat dihancurkan. Metode destruktor untuk kelas proyek adalah destroy() dengan huruf kecil d untuk konsistensi camelCase di seluruh metode basis kode, serta untuk membedakan antara kelas proyek dan instance Roblox.

Peran metode destroy() adalah untuk menghancurkan instance apa pun yang dibuat oleh objek, memutuskan koneksi apa pun, dan memanggil destroy() pada objek anak mana pun. Ini sangat penting untuk koneksi karena instance dengan koneksi aktif tidak dibersihkan oleh pengumpul sampah Luau, bahkan jika tidak ada referensi ke instance atau koneksi ke instance yang tersisa.

Singleton

Singleton, seperti namanya, adalah kelas di mana hanya satu objek yang dapat ada. Mereka adalah setara proyek dengan Layanan Roblox. Alih-alih menyimpan referensi ke objek singleton dan meneruskannya di dalam kode Luau, Tanaman memanfaatkan fakta bahwa memerlukan ModuleScript menyimpan nilai yang dikembalikan. Ini berarti bahwa memerlukan ModuleScript singleton yang sama dari tempat yang berbeda secara konsisten memberikan objek yang sama yang dikembalikan. Satu-satunya pengecualian untuk aturan ini adalah jika lingkungan yang berbeda (klien atau server) mengakses ModuleScript.

Singleton dibedakan dari kelas yang dapat diinstansiasi dengan fakta bahwa mereka tidak memiliki metode new(). Sebaliknya, objek beserta metode dan statusnya dikembalikan langsung melalui ModuleScript. Karena singleton tidak diinstansiasi, sintaks self tidak digunakan dan metode dipanggil dengan titik (.) daripada titik dua (:).

Pemeriksaan tipe ketat

Luau mendukung pengetikan bertahap yang berarti Anda bebas menambahkan definisi tipe opsional ke beberapa atau semua kode Anda. Dalam proyek ini, pemeriksaan tipe strict digunakan untuk setiap skrip. Ini adalah opsi paling ketat untuk alat Analisis Skrip Roblox dan dengan demikian paling mungkin menangkap kesalahan tipe sebelum runtime.

Sintaks kelas bertipe

Pendekatan yang sudah mapan untuk membuat kelas di Lua didokumentasikan dengan baik, namun tidak cocok untuk pengetikan Luau yang kuat. Di Luau, pendekatan termudah untuk mendapatkan tipe kelas adalah metode typeof():

type ClassType = typeof(Class.new())

Ini berfungsi tetapi tidak terlalu berguna ketika kelas Anda diinisiasi dengan nilai yang hanya ada saat runtime, misalnya objek Player. Selain itu, asumsi yang dibuat dalam sintaks kelas Lua idiomatik adalah bahwa mendeklarasikan metode pada kelas self akan selalu menjadi instance dari kelas itu; ini bukan asumsi yang dapat dibuat oleh mesin inferensi tipe.

Untuk mendukung inferensi tipe ketat, proyek Tanaman menggunakan solusi yang berbeda dari sintaks kelas Lua idiomatik dalam sejumlah cara, beberapa di antaranya mungkin terasa tidak intuitif:

  • Definisi self diduplikasi, baik dalam deklarasi tipe maupun dalam konstruktor. Ini memperkenalkan beban pemeliharaan, tetapi peringatan akan ditandai jika kedua definisi tidak sinkron satu sama lain.
  • Metode kelas dideklarasikan dengan titik, sehingga self dapat secara eksplisit dideklarasikan sebagai tipe ClassType. Metode masih dapat dipanggil dengan titik dua seperti yang diharapkan.
--!strict
local MyClass = {}
MyClass.__index = MyClass
export type ClassType = typeof(setmetatable(
{} :: {
property: number,
},
MyClass
))
function MyClass.new(property: number): ClassType
local self = {
property = property,
}
setmetatable(self, MyClass)
return self
end
function MyClass.addOne(self: ClassType)
self.property += 1
end
return MyClass

Cast tipe setelah penjaga logis

Pada saat penulisan, tipe nilai tidak dipersempit setelah pernyataan penjaga kondisional. Sebagai contoh, setelah penjaga di bawah ini, tipe optionalParameter tidak dipersempit menjadi number.

--!strict
local function foo(optionalParameter: number?)
if not optionalParameter then
return
end
print(optionalParameter + 1)
end

Untuk mengatasi ini, variabel baru dibuat setelah penjaga ini dengan tipe yang secara eksplisit di-cast.

--!strict
local function foo(optionalParameter: number?)
if not optionalParameter then
return
end
local parameter = optionalParameter :: number
print(parameter + 1)
end

Menelusuri hierarki DataModel

Dalam beberapa kasus, basis kode perlu menelusuri hierarki model data dari pohon objek yang dibuat saat runtime. Ini menghadirkan tantangan menarik untuk pemeriksaan tipe. Pada saat penulisan, tidak mungkin untuk mendefinisikan hierarki model data generik sebagai tipe. Akibatnya, ada kasus di mana satu-satunya informasi tipe yang tersedia untuk struktur model data adalah tipe dari instance tingkat atas.

Salah satu pendekatan untuk tantangan ini adalah melakukan cast ke any dan kemudian memperbaiki. Sebagai contoh:

local function enableVendor(vendor: Model)
local zonePart: BasePart = (vendor :: any).ZonePart
end

Masalah dengan pendekatan ini adalah bahwa ini mempengaruhi keterbacaan. Sebagai gantinya, proyek ini menggunakan modul generik bernama getInstance untuk menelusuri hierarki model data yang melakukan cast ke any secara internal.

local function enableVendor(vendor: Model)
local zonePart: BasePart = getInstance(vendor, "ZonePart")
end

Seiring dengan berkembangnya pemahaman mesin tipe tentang model data, mungkin pola seperti ini tidak lagi diperlukan.

Antarmuka pengguna

Tanaman mencakup berbagai antarmuka pengguna 2D yang kompleks dan sederhana. Ini termasuk item tampilan kepala non-interaktif (HUD) seperti penghitung koin dan menu interaktif kompleks seperti toko.

Pendekatan UI

Anda dapat membandingkan UI Roblox UI dengan DOM HTML, karena ini adalah hierarki objek yang menggambarkan apa yang seharusnya dilihat pengguna. Pendekatan untuk membuat dan memperbarui UI Roblox secara luas dibagi menjadi praktik imperatif dan deklaratif.

PendekatanKeuntungan dan kerugian
Imperatif

Dalam pendekatan imperatif, UI diperlakukan seperti hierarki instance lainnya di Roblox. Struktur UI dibuat sebelum runtime di Studio dan ditambahkan ke model data, biasanya langsung di StarterGui. Kemudian, saat runtime, kode memanipulasi bagian tertentu dari UI untuk mencerminkan status yang diinginkan oleh pembuat.

Pendekatan ini memiliki beberapa keuntungan. Anda dapat membuat UI dari awal di Studio dan menyimpannya di model data. Ini adalah pengalaman pengeditan yang sederhana dan visual yang dapat mempercepat pembuatan UI. Karena kode UI imperatif hanya memperhatikan apa yang perlu diubah, ini juga membuat perubahan UI sederhana mudah diimplementasikan.

Salah satu kerugian yang mencolok adalah bahwa, karena pendekatan UI imperatif memerlukan status untuk diimplementasikan secara manual dalam bentuk transformasi, representasi status yang kompleks dapat menjadi sangat sulit ditemukan dan diperbaiki. Kesalahan sering muncul saat mengembangkan kode UI imperatif, terutama ketika status dan UI menjadi tidak sinkron karena beberapa pembaruan berinteraksi dalam urutan yang tidak terduga.

Tantangan lain dengan pendekatan imperatif adalah bahwa lebih sulit untuk memecah UI menjadi komponen yang bermakna yang dapat dideklarasikan sekali dan digunakan kembali. Karena seluruh pohon UI dideklarasikan pada waktu edit, pola umum mungkin diulang di beberapa bagian model data.

Deklaratif

Dalam pendekatan deklaratif, status yang diinginkan dari instance UI dideklarasikan secara eksplisit, dan implementasi efisien dari status ini diabstraksikan oleh pustaka seperti Roact atau Fusion.

Keuntungan dari pendekatan ini adalah implementasi status menjadi sepele dan Anda hanya perlu menggambarkan bagaimana Anda ingin UI Anda terlihat. Ini membuat mengidentifikasi dan menyelesaikan bug menjadi jauh lebih mudah.

Kerugian utama adalah harus mendeklarasikan seluruh pohon UI dalam kode. Pustaka seperti Roact dan Fusion memiliki sintaks untuk mempermudah ini, tetapi tetap merupakan proses yang memakan waktu dan pengalaman pengeditan yang kurang intuitif saat menyusun UI.

Tanaman menggunakan pendekatan imperatif dengan anggapan bahwa menunjukkan transformasi secara langsung memberikan gambaran yang lebih efektif tentang bagaimana UI dibuat dan dimanipulasi di Roblox. Ini tidak akan mungkin dilakukan dengan pendekatan deklaratif. Beberapa struktur dan logika UI yang diulang juga diabstraksikan menjadi komponen yang dapat digunakan kembali untuk menghindari jebakan umum dalam desain UI imperatif.

Arsitektur tingkat tinggi

Diagram arsitektur UI proyek Tanaman

Lapisan dan komponen

Dalam Tanaman, semua struktur UI adalah baik Layer atau Component.

  • Layer didefinisikan sebagai singleton pengelompokan tingkat atas yang membungkus struktur UI prefabrikasi di ReplicatedStorage. Sebuah lapisan dapat berisi sejumlah komponen, atau dapat mengenkapsulasi logikanya sendiri sepenuhnya. Contoh lapisan adalah menu inventaris atau indikator jumlah koin di tampilan kepala.
  • Component adalah elemen UI yang dapat digunakan kembali. Ketika objek komponen baru diinstansiasi, ia mengkloning template prefabrikasi dari ReplicatedStorage. Komponen dapat berisi komponen lain. Contoh komponen adalah kelas tombol generik atau konsep daftar item.

Penanganan tampilan

Masalah manajemen UI yang umum adalah penanganan tampilan. Proyek ini memiliki berbagai menu dan item HUD, beberapa di antaranya mendengarkan input pengguna, dan manajemen yang hati-hati tentang kapan mereka terlihat atau diaktifkan diperlukan.

Tanaman mendekati masalah ini dengan sistem UIHandler yang mengelola kapan lapisan UI harus atau tidak harus terlihat. Semua lapisan UI dalam game dikategorikan sebagai HUD atau Menu dan visibilitasnya dikelola oleh aturan berikut:

  • Status diaktifkan dari lapisan Menu dan HUD dapat diubah.
  • Lapisan HUD yang diaktifkan hanya ditampilkan jika tidak ada lapisan Menu yang diaktifkan.
  • Lapisan Menu yang diaktifkan disimpan dalam tumpukan, dan hanya satu lapisan Menu yang terlihat pada satu waktu. Ketika lapisan Menu diaktifkan, ia dimasukkan ke depan tumpukan dan ditampilkan. Ketika lapisan Menu dinonaktifkan, ia dihapus dari tumpukan dan lapisan Menu yang diaktifkan berikutnya dalam antrean ditampilkan.

Pendekatan ini intuitif karena memungkinkan menu dinavigasi dengan riwayat. Jika satu menu dibuka dari menu lain, menutup menu baru akan menampilkan menu lama lagi.

Singleton lapisan UI mendaftar diri mereka dengan UIHandler dan diberikan sinyal yang dipicu ketika visibilitasnya harus berubah.

Bacaan lebih lanjut

Dari tinjauan menyeluruh tentang proyek Tanaman, Anda mungkin ingin menjelajahi panduan berikut yang lebih mendalam tentang konsep dan topik terkait.

  • Model Klien-Server — Tinjauan tentang model klien-server di Roblox.
  • Luau — Rincian tentang Luau, bahasa skrip yang dibuat oleh Roblox yang diturunkan dari Lua 5.1.
  • Acara Jarak Jauh dan Callback — Semua tentang acara jaringan jarak jauh dan callback untuk komunikasi di seluruh batas klien-server.
  • UI — Rincian tentang objek antarmuka pengguna dan desain di Roblox.
©2026 Roblox Corporation. Roblox, logo Roblox, dan Powering Imagination termasuk dalam merek dagang kami yang terdaftar dan tidak terdaftar di AS dan negara lainnya.