Progetto di riferimento della pianta

*Questo contenuto è tradotto usando AI (Beta) e potrebbe contenere errori. Per visualizzare questa pagina in inglese, clicca qui.

Plant è un'esperienza di riferimento in cui i giocatori piantano e annaffiano semi, in modo da poter successivamente raccogliere e vendere le piante risultanti.

Banner del progetto Plant

Il progetto si concentra su casi d'uso comuni che potresti incontrare nello sviluppo di un'esperienza su Roblox. Dove applicabile, troverai note sui compromessi, le scelte e le giustificazioni delle varie implementazioni, in modo da poter prendere la decisione migliore per le tue esperienze.

Ottieni il file

  1. Naviga alla pagina dell'esperienza Plant.
  2. Fai clic sul pulsante e Modifica in Studio.

Casi d'uso

Plant copre i seguenti casi d'uso:

  • Persistenza dei dati di sessione e dei dati del giocatore
  • Gestione della visualizzazione dell'interfaccia utente
  • Rete client-server
  • Esperienza per il primo utente (FTUE)
  • Acquisti di valuta hard e soft

In aggiunta, questo progetto risolve insiemi più ristretti di problemi applicabili a molte esperienze, tra cui:

  • Personalizzazione di un'area nel luogo associata a un giocatore
  • Gestione della velocità di movimento del personaggio del giocatore
  • Creazione di un oggetto che segue i personaggi
  • Rilevamento di qual parte del mondo si trova un personaggio

Nota che ci sono diversi casi d'uso in questa esperienza che sono troppo piccoli, troppo di nicchia o non dimostrano una soluzione a una sfida di design interessante; questi non sono coperti.

Struttura del progetto

La prima decisione nella creazione di un'esperienza è decidere come strutturare il progetto, che include principalmente dove posizionare istanze specifiche nel modello dei dati e come organizzare e strutturare i punti di ingresso sia per il codice client che per il server.

Modello dati

La seguente tabella descrive quali servizi contenitore nel modello dei dati le istanze sono posizionate.

ServizioTipi di istanze
Workspace

Contiene modelli statici che rappresentano il mondo 3D, nello specifico parti del mondo che non appartengono a nessun giocatore. Non è necessario creare, modificare o distruggere dinamicamente queste istanze durante il runtime, quindi è accettabile lasciarle qui.

C'è anche un Folder vuoto, a cui verranno aggiunti i modelli delle fattorie dei giocatori durante il runtime.

Lighting

Effetti atmosferici e di illuminazione.

ReplicatedFirst

Contiene il più piccolo sottoinsieme possibile di istanze necessarie per visualizzare la schermata di caricamento e inizializzare l'esperienza. Maggiore è il numero di istanze posizionate in ReplicatedFirst, più lungo sarà l'attesa affinché si replicano prima che il codice in ReplicatedFirst possa essere eseguito.

  • Nella cartella Instances esiste la GUI della schermata di caricamento.
  • Nella cartella Source esiste il codice della schermata di caricamento e il codice necessario per attendere il caricamento del resto dell'esperienza. Lo script start di LocalScript è il punto di ingresso per tutto il codice lato client nel progetto.
ReplicatedStorage

Funziona come contenitore di archiviazione per tutte le istanze a cui è necessario accedere sia dal client che dal server.

  • Nella cartella Dependencies esistono alcune librerie di terze parti utilizzate dal progetto.
  • Nella cartella Instances esiste un'ampia gamma di istanze prefabbricate.
  • Nella cartella Source esiste tutto il codice non necessario per il processo di caricamento che deve essere accessibile sia dal client che dal server.
ServerScriptService

Contiene uno Script che funge da punto di ingresso per tutto il codice lato server nel progetto.

ServerStorage

Funziona come contenitore di archiviazione per tutte le istanze che non devono essere replicate sul client.

  • Nella cartella Instances esiste un modello Farm template. Una copia di questo verrà posizionata in Workspace quando il giocatore entra nell'esperienza, dove verrà replicata a tutti i giocatori.
  • Nella cartella Source esiste tutto il codice esclusivo per il server.
SoundService

Contiene gli oggetti Sound utilizzati per gli effetti sonori nell'esperienza. Sotto SoundService, questi oggetti Sound non hanno posizione e non sono simulati nello spazio 3D.

Punti di ingresso

La maggior parte dei progetti organizza il codice all'interno di ModuleScripts riutilizzabili che possono essere importati in tutto il codice. ModuleScripts sono riutilizzabili, ma non vengono eseguiti da soli; devono essere importati da uno Script o uno LocalScript. Molti progetti Roblox avranno un gran numero di oggetti Script e LocalScript, ciascuno relativo a un comportamento o un sistema particolare nell'esperienza, creando più punti di ingresso.

Per il microgioco Plant, viene implementato un approccio diverso attraverso un singolo LocalScript che funge da punto di ingresso per tutto il codice client, e un singolo Script che funge da punto di ingresso per tutto il codice server. L'approccio corretto per il tuo progetto dipende dai tuoi requisiti, ma un singolo punto di ingresso fornisce un maggiore controllo sull'ordine in cui i sistemi vengono eseguiti.

Le seguenti liste descrivono i compromessi di entrambi gli approcci:

  • Un singolo Script e un singolo LocalScript coprono rispettivamente il codice server e client.
  • Maggiore controllo sull'ordine in cui vengono avviati i diversi sistemi perché tutto il codice è inizializzato da un unico script.
  • La possibilità di passare oggetti per riferimento tra i sistemi.

Architettura di alto livello dei sistemi

I sistemi di livello superiore nel progetto sono dettagliati di seguito. Alcuni di questi sistemi sono sostanzialmente più complessi di altri e, in molti casi, la loro funzionalità è astratta attraverso una gerarchia di altre classi.

Diagramma dell'architettura dei sistemi del progetto Plant

Ognuno di questi sistemi è un "singleton", in quanto è una classe non istanziabile che viene invece inizializzata dallo script di avvio client o server pertinente. Puoi leggere di più sul modello singleton più avanti in questa guida.

Server

I seguenti sistemi sono associati al server.

SistemaDescrizione
Network
  • Crea tutte le istanze RemoteEvent e RemoteFunction.
  • Espone metodi per inviare e ascoltare messaggi dal client.
  • Validazione dei tipi per gli argomenti ricevuti dal client durante il runtime.
PlayerDataServer
  • Salva e carica dati persistenti del giocatore utilizzando DataStoreService.
  • Memorizza i dati del giocatore in memoria e replica le mutazioni sul client.
  • Espone segnali e metodi per iscriversi, interrogare e aggiornare i dati del giocatore.
Market
  • Gestisce le transazioni di valuta soft dal client.
  • Espone un metodo per vendere piante raccolte.
CollisionGroupManager
  • Assegna modelli dei personaggi dei giocatori a gruppi di collisione.
  • Configura i gruppi di collisione in modo che i personaggi dei giocatori non possano collidere con i carri delle piante.
FarmManagerServer
  • Ricrea il modello della fattoria di un giocatore dai suoi dati quando entra nell'esperienza.
  • Rimuove il modello della fattoria quando un giocatore esce.
  • Aggiorna i dati del giocatore quando la fattoria di un giocatore viene modificata.
  • Espone un metodo per accedere alla classe Farm associata a un dato giocatore.
PlayerObjectsContainer
  • Crea vari oggetti associati alla durata di vita di un giocatore e fornisce un metodo per recuperarli.
TagPlayers
  • Aggiunge tag di CollectionService a tutti gli oggetti dei giocatori e dei personaggi.
FtueManagerServer
  • Durante il FTUE, esegue ciascuna fase e attende che venga completata.
CharacterSpawner
  • Respawna i personaggi quando muoiono. Nota che Players.CharacterAutoLoads è stato disabilitato in modo che il spawning venga messo in pausa fino al caricamento dei dati del giocatore.

Client

I seguenti sistemi sono associati al client.

SistemaDescrizione
Network
  • Attende che il server crei tutte le istanze RemoteEvent e RemoteFunction.
  • Espone metodi per inviare e ascoltare messaggi da e verso il server.
  • Imponendo la validazione dei parametri di tipo durante il runtime.
  • Esegue pcall() su funzioni remote.
PlayerDataClient
  • Memorizza i dati del giocatore locale in memoria.
  • Espone metodi e segnali per interrogare e iscriversi alle modifiche nei dati del giocatore.
MarketClient
  • Espone un metodo per richiedere al server di acquistare un oggetto per valuta soft.
LocalWalkJumpManager
  • Espone metodi per modificare la WalkSpeed o JumpHeight di un personaggio tramite moltiplicatori per evitare conflitti quando si modificano questi valori da più posti.
FarmManagerClient
  • Ascolta l'applicazione di tag specifici di CollectionService alle istanze e crea "componenti" che aggiungono comportamento a queste istanze. Un "componente" si riferisce a una classe creata quando un tag di CollectionService viene aggiunto a un'istanza e distrutta quando viene rimosso; questi vengono utilizzati per i prompt CTA nella fattoria e per varie classi che comunicano lo stato della fattoria al giocatore.
UISetup
  • Inizializza tutti i livelli dell'interfaccia utente.
  • Configura alcuni livelli per essere visibili solo in sezioni fisiche del mondo.
  • Collega un effetto speciale della camera quando i menu sono attivati.
FtueManagerClient
  • Configura le fasi del FTUE sul client.
CharacterSprint
  • Usa LocalWalkJumpManager per aumentare la WalkSpeed quando un personaggio del giocatore è al di fuori della propria fattoria.

Comunicazione client-server

La maggior parte delle esperienze Roblox comporta un elemento di comunicazione tra client e server. Ciò può includere la richiesta del client al server di eseguire una determinata azione e il server che replica aggiornamenti al client.

In questo progetto, la comunicazione client-server viene mantenuta il più generica possibile limitando l'uso degli oggetti RemoteEvent e RemoteFunction in modo da ridurre la quantità di regole speciali da tenere traccia. Questo progetto utilizza i seguenti metodi, in ordine di preferenza:

Replica tramite il sistema di dati dei giocatori

Il sistema di dati dei giocatori consente di associare dati al giocatore che persistono tra le sessioni di salvataggio. Questo sistema fornisce replica dal client al server e un insieme di API che possono essere utilizzate per interrogare i dati e iscriversi a modifiche, rendendolo ideale per replicare modifiche allo stato del giocatore dal server al client.

Ad esempio, piuttosto che attivare un UpdateCoins RemoteEvent su misura per informare il client di quanti soldi ha, puoi chiamare il seguente e lasciare che il client si iscriva tramite l'evento PlayerDataClient.updated.


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

Certo, questo è utile solo per la replica dal server al client e per i valori che desideri mantenere tra le sessioni, ma questo si applica a un sorprendente numero di casi nel progetto, tra cui:

  • L'attuale fase FTUE
  • L'inventario del giocatore
  • L'ammontare di monete che il giocatore ha
  • Lo stato della fattoria del giocatore

Replica tramite attributi

In situazioni in cui il server deve replicare un valore personalizzato al client specifico per un determinato Instance, puoi utilizzare attributi. Roblox replica automaticamente i valori degli attributi, quindi non hai bisogno di mantenere percorsi di codice per replicare lo stato associato a un oggetto. Un altro vantaggio è che questa replica avviene insieme all'istanza stessa.

Questo è particolarmente utile per le istanze create durante il runtime, poiché gli attributi impostati su una nuova istanza prima che venga parentata al modello dei dati si replicano in modo atomico con l'istanza stessa. Questo evita la necessità di scrivere codice per "attendere" che dati aggiuntivi vengano replicati tramite un RemoteEvent o un StringValue.

Puoi anche leggere direttamente gli attributi dal modello dei dati, sia dal client che dal server, con il metodo GetAttribute() e iscriversi a modifiche con il metodo GetAttributeChangedSignal(). Nel progetto Plant, questo approccio viene utilizzato per, tra le altre cose, replicare l'attuale stato delle piante ai client.

Replica tramite tag

CollectionService ti permette di applicare un tag di stringa a un Instance. Questo è utile per categorizzare le istanze e replicare quella categorizzazione al client.

Ad esempio, il tag CanPlant viene applicato sul server per segnalare al client che un determinato vaso è in grado di ricevere una pianta.

Messaggistica direttamente tramite il modulo di rete

Per situazioni in cui nessuna delle opzioni precedenti si applica, puoi utilizzare chiamate di rete personalizzate attraverso il modulo Network. Questa è l'unica opzione nel progetto che consente la comunicazione client-server e quindi è utile per trasmettere richieste del client e ricevere una risposta dal server.

Plant utilizza chiamate di rete dirette per una varietà di richieste client, inclusi:

  • Annaffiare una pianta
  • Piantare un seme
  • Acquistare un oggetto

Lo svantaggio di questo approccio è che ciascun messaggio individuale richiede una configurazione speciale che può aumentare la complessità del progetto, anche se questo è stato evitato ovunque possibile, in particolare per quanto riguarda la comunicazione dal server al client.

Classi e singleton

Le classi nel progetto Plant, come le istanze su Roblox, possono essere create e distrutte. La sua sintassi di classe è ispirata all'approccio idiomatico di Lua per la programmazione orientata agli oggetti con una serie di modifiche per consentire il supporto della verifica dei tipi rigorosi.

Istanze

Molte classi nel progetto sono associate a una o più Instances. Gli oggetti di una data classe vengono creati utilizzando un metodo new(), coerente con il modo in cui le istanze sono create in Roblox utilizzando Instance.new().

Questo modello viene generalmente utilizzato per oggetti la cui classe ha una rappresentazione fisica nel modello dei dati e la classe estende la sua funzionalità. Un buon esempio è BeamBetween che crea un oggetto Beam tra due dati Attachment e mantiene quegli attachment orientati in modo che il raggio sia sempre rivolto verso l'alto. Queste istanze potrebbero essere clonate da una versione prefabbricata in ReplicatedStorage o passate a new() come argomento e memorizzate all'interno dell'oggetto sotto self.

Istanze corrispondenti

Come notato sopra, molte classi in questo progetto hanno una rappresentanza nel modello dei dati, un'istanza che corrisponde alla classe e che viene manipolata da essa.

Piuttosto che creare queste istanze quando un oggetto di classe viene istanziato, il codice generalmente sceglie di Clone() una versione prefabbricata dell'istanza Instance memorizzata sotto ReplicatedStorage o ServerStorage. Anche se sarebbe possibile serializzare le proprietà di queste istanze e crearle da zero nelle funzioni new() della classe, farlo renderebbe molto scomoda la modifica degli oggetti e renderebbe più difficile per un lettore interpretarli. Inoltre, clonare un'istanza è generalmente un'operazione più veloce rispetto a creare una nuova istanza e personalizzarne le proprietà durante il runtime.

Composizione

Sebbene l'ereditarietà sia possibile in Luau utilizzando metatabelle, il progetto opta invece di consentire alle classi di estendersi a vicenda tramite composizione. Quando si combinano classi tramite composizione, l'oggetto "figlio" viene istanziato nel metodo new() della classe ed è incluso come membro sotto self.

Per un esempio di questo in azione, vedere la classe CloseButton che avvolge la classe Button.

Cleanup

Allo stesso modo in cui un Instance può essere distrutto con il metodo Destroy(), le classi che possono essere istanziate possono anche essere distrutte. Il metodo distruttore per le classi del progetto è destroy() con una d minuscola per coerenza con camelCase attraverso i metodi del codice, oltre a distinguere tra le classi del progetto e le istanze di Roblox.

Il ruolo del metodo destroy() è quello di distruggere qualsiasi istanza creata dall'oggetto, disconnettere eventuali collegamenti e chiamare destroy() su eventuali oggetti figli. Questo è particolarmente importante per le connessioni perché le istanze con connessioni attive non vengono pulite dal garbage collector Luau, anche se non rimangono riferimenti all'istanza o connessioni all'istanza.

Singleton

I singleton, come suggerisce il nome, sono classi per le quali può esistere solo un oggetto. Sono l'equivalente del progetto dei Servizi di Roblox. Piuttosto che memorizzare un riferimento all'oggetto singleton e passarne un'istanza nel codice Luau, Plant sfrutta il fatto che richiedere un ModuleScript memorizza il suo valore restituito. Questo significa che richiedere lo stesso ModuleScript singleton da luoghi diversi fornisce costantemente lo stesso oggetto restituito. L'unica eccezione a questa regola sarebbe se ambienti diversi (client o server) accedessero allo ModuleScript.

I singleton si distinguono dalle classi istanziabili per il fatto che non hanno un metodo new(). Piuttosto, l'oggetto insieme ai suoi metodi e stato vengono restituiti direttamente tramite lo ModuleScript. Poiché i singleton non vengono istanziati, la sintassi self non viene utilizzata e i metodi vengono invece chiamati con un punto (.) piuttosto che con due punti (:).

Verifica di tipo rigorosa

Luau supporta la tipizzazione graduale, il che significa che sei libero di aggiungere definizioni di tipo opzionali a parte o tutto il tuo codice. In questo progetto, la verifica di tipo strict è utilizzata per ogni script. Questa è l'opzione meno permissiva per lo strumento Analisi degli script di Roblox e quindi la più probabile per catturare errori di tipo prima del runtime.

Sintassi di classe tipizzata

L'approccio consolidato per creare classi in Lua è ben documentato, tuttavia non è ben adattato alla tipizzazione rigorosa di Luau. In Luau, l'approccio più semplice per ottenere il tipo di una classe è il metodo typeof():


type ClassType = typeof(Class.new())

Questo funziona ma non è molto utile quando la tua classe viene inizializzata con valori che esistono solo durante il runtime, ad esempio gli oggetti Player. Inoltre, l'assunzione fatta nella sintassi idiomatica delle classi Lua è che dichiarare un metodo su una classe self sarà sempre un'istanza di quella classe; questa non è un'assunzione che il motore di inferenza dei tipi può fare.

Per supportare l'inferenza di tipo rigorosa, il progetto Plant utilizza una soluzione che differisce dalla sintassi idiomatica delle classi di Lua in diversi modi, alcuni dei quali potrebbero sembrare non intuitivi:

  • La definizione di self è duplicata, sia nella dichiarazione del tipo che nel costruttore. Questo introduce un onere di manutenibilità, ma verranno segnalati avvisi se le due definizioni non rimangono sincronizzate.
  • I metodi delle classi vengono dichiarati con un punto, in modo che self possa essere esplicitamente dichiarato come tipo ClassType. I metodi possono comunque essere chiamati con due punti come previsto.

--!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

Tipi di cast dopo le guardie logiche

Al momento della scrittura, il tipo di un valore non viene ristretto dopo una dichiarazione condizionale di guardia. Ad esempio, seguendo la guardia di seguito, il tipo di optionalParameter non viene ristretto a number.


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

Per mitigare questo, vengono creati nuovi variabili dopo queste guardie con il tipo esplicitamente castato.


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

Traversare le gerarchie del DataModel

In alcuni casi, il codice deve attraversare la gerarchia del modello dei dati di un albero di oggetti creati durante il runtime. Questo presenta una sfida interessante per la verifica dei tipi. Al momento della scrittura, non è possibile definire una gerarchia generica del modello di dati come tipo. Di conseguenza, ci sono casi in cui l'unica informazione di tipo disponibile per una struttura del modello di dati è il tipo dell'istanza di alto livello.

Un approccio a questa sfida è effettuare un cast a any e poi raffinare. Ad esempio:


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

Il problema con questo approccio è che influisce sulla leggibilità. Invece, il progetto utilizza un modulo generico chiamato getInstance per attraversare gerarchie del modello dei dati che effettua internamente un cast a any.


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

Man mano che la comprensione del motore di tipo del modello dei dati evolve, è possibile che modelli come questo non siano più necessari.

Interfaccia utente

Plant include una varietà di interfacce utente 2D complesse e semplici. Queste includono elementi non interattivi dell'interfaccia visiva (HUD) come il contatore di monete e menu interattivi complessi come il negozio.

Approccio UI

Puoi confrontare liberamente le UI di Roblox con il DOM HTML, poiché è una gerarchia di oggetti che descrivono cosa dovrebbe vedere l'utente. Gli approcci per creare e aggiornare una UI di Roblox sono ampiamente divisi in pratiche imperative e declarative.

ApproccioVantaggi e svantaggi
Imperativo

Nel approccio imperativo, l'interfaccia utente è trattata come qualsiasi altra gerarchia di istanze su Roblox. La struttura dell'interfaccia utente viene creata prima del runtime in Studio e aggiunta al modello dati, tipicamente direttamente in StarterGui. Poi, durante il runtime, il codice manipola pezzi specifici dell'interfaccia utente per riflettere lo stato richiesto dal creatore.

Questo approccio ha alcuni vantaggi. Puoi creare l'interfaccia da zero in Studio e memorizzarla nel modello di dati. Questa è un'esperienza di modifica semplice e visiva che può accelerare la creazione dell'interfaccia utente. Poiché il codice dell'interfaccia utente imperativa si preoccupa solo di cosa deve essere cambiato, rende anche facili da implementare piccole modifiche all'interfaccia utente.

Un notevole svantaggio è che, poiché gli approcci UI imperativi richiedono che lo stato sia implementato manualmente sotto forma di trasformazioni, rappresentazioni complesse dello stato possono diventare molto difficili da trovare e debug. È comune che emergano errori durante lo sviluppo di codice UI imperativo, specialmente quando lo stato e l'interfaccia utente diventano desincronizzati a causa di aggiornamenti multipli che interagiscono in un ordine inaspettato.

Un'altra sfida con gli approcci imperativi è che è più difficile suddividere l'interfaccia utente in componenti significativi che possono essere dichiarati una sola volta e riutilizzati. Poiché l'intero albero dell'interfaccia utente viene dichiarato nella fase di modifica, modelli comuni possono essere ripetuti in più parti del modello di dati.

Declarativo

Nell'approccio dichiarativo, lo stato desiderato delle istanze UI viene dichiarato esplicitamente, e l'implementazione efficiente di questo stato è astratta da librerie come Roact o Fusion.

Il vantaggio di questo approccio è che l'implementazione dello stato diventa banale e devi solo descrivere come vuoi che appaia la tua UI. Questo rende molto più facile identificare e risolvere i bug.

Lo svantaggio principale è dover dichiarare l'intero albero UI nel codice. Librerie come Roact e Fusion hanno sintassi per semplificare questo, ma è comunque un processo che richiede tempo e un'esperienza di modifica meno intuitiva quando si compone l'interfaccia utente.

Plant utilizza un approccio imperativo con l'idea che mostrare le trasformazioni direttamente fornisce una visione più efficace di come l'interfaccia utente venga creata e manipolata su Roblox. Questo non sarebbe possibile con un approccio dichiarativo. Alcune strutture e logiche UI ripetute sono anche astratte in componenti riutilizzabili per evitare un difetto comune nel design UI imperativo.

Architettura di alto livello

Diagramma dell'architettura UI del progetto Plant

Strato e componenti

In Plant, tutte le strutture UI sono o uno Layer o un Component.

  • Layer è definito come un singleton di raggruppamento di alto livello che avvolge strutture UI prefabbricate in ReplicatedStorage. Un layer può contenere un certo numero di componenti, oppure può incapsulare completamente la propria logica. Esempi di layer sono il menu inventario o l'indicatore del numero di monete nell'interfaccia visiva.
  • Component è un elemento UI riutilizzabile. Quando un nuovo oggetto componente viene istanziato, clona un template prefabbricato da ReplicatedStorage. I componenti possono a loro volta contenere altri componenti. Esempi di componenti sono una classe di pulsanti generici o il concetto di un elenco di oggetti.

Gestione della vista

Un comune problema nella gestione dell'interfaccia utente è la gestione delle viste. Questo progetto ha una serie di menu e elementi HUD, alcuni dei quali ascoltano l'input dell'utente, e una gestione attenta di quando sono visibili o abilitati è necessaria.

Plant affronta questo problema con il suo sistema UIHandler che gestisce quando un livello dell'interfaccia utente dovrebbe o non dovrebbe essere visibile. Tutti i livelli dell'interfaccia utente nell'esperienza sono categorizzati come HUD o Menu e la loro visibilità è gestita dalle seguenti regole:

  • Lo stato abilitato dei livelli Menu e HUD può essere attivato.
  • I livelli HUD abilitati vengono mostrati solo se nessun livello Menu è abilitato.
  • I livelli Menu abilitati sono memorizzati in uno stack, e solo un livello Menu è visibile alla volta. Quando un livello Menu è abilitato, viene inserito in cima allo stack e mostrato. Quando un livello Menu è disabilitato, viene rimosso dallo stack e il prossimo livello Menu abilitato nella coda viene mostrato.

Questo approccio è intuitivo perché consente la navigazione nei menu con cronologia. Se un menu viene aprito da un altro menu, chiudere il nuovo menu mostrerà di nuovo il vecchio menu.

Ulteriori letture

Da questa panoramica approfondita del progetto Plant, potresti voler esplorare le seguenti guide che approfondiscono ulteriormente concetti e argomenti correlati.

  • Modello Client-Server — Una panoramica del modello client-server in Roblox.
  • Luau — Dettagli su Luau, il linguaggio di scripting creato da Roblox discendente da Lua 5.1.
  • Eventi e Callback Remoti — Tutto su eventi di rete remota e callback per la comunicazione attraverso il confine client-server.
  • UI — Dettagli sugli oggetti e sul design dell'interfaccia utente su Roblox.
© 2026 Roblox Corporation. Roblox, il logo Roblox e Powering Imagination sono tra i nostri marchi registrati e non registrati negli Stati Uniti. e altri paesi.