Pflanze ist eine Referenz-Erfahrung, in der Spieler Pflanzen pflanzen und Wasser sammeln, damit sie später ernten und verkaufen können.

Das Projekt konzentriert sich auf häufige Anwendungsfälle, die Sie beim Entwickeln einer Erfahrung auf Roblox treffen könnten.Wo es geltendist, findest du Notizen über Abwägungen, Kompromisse und die Rationale verschiedener Implementierungsoptionen, damit du die beste Entscheidung für deine eigenen Erfahrungen treffen kannst.
Holen Sie sich die Datei
- Navigiere zur Pflanze-Erfahrungsseite.
- Klicken Sie auf die Schaltfläche ⋯ und In Studio bearbeiten .
Verwendungsfälle
Pflanze deckt die folgenden Anwendungsfälle ab:
- Sitzungsdaten und Spielerdatenbeständigkeit
- UI-Ansichtsverwaltung
- Client-Server-Netzwerk
- Erstmalige Benutzererfahrung (FTUE)
- Harte und weiche Währungskäufe
Darüber hinaus löst dieses Projekt enger geordnete Probleme, die für viele Erfahrungen anwendbar sind, einschließlich:
- Anpassung eines Bereichs an einem Ort, der mit einem Spieler:inverbunden ist
- Verwaltung der Bewegungsgeschwindigkeit des Spielerscharakters
- Ein Objekt erstellen, das Charaktere umfolgt
- Erkennen, in welchem Teil der Welt sich ein Charakter befindet
Beachte, dass es mehrere Anwendungsfälle in diesem Erlebnis gibt, die zu klein, zu speziell oder nicht in der Lage sind, eine Lösung für eine interessante Designherausforderung zu demonstrieren; diese sind nicht abgedeckt.
Projektstruktur
Die erste Entscheidung beim Erstellen eines Erlebnisses ist die Entscheidung, wie das Projekt strukturiert werden soll, das hauptsächlich darin besteht, wo spezifische Instanzen im Datenmodell platziert werden sollen, und wie Eintrittspunkte für Client- und Codesstrukturiert und organisiert werden.
Modell
Die folgende Tabelle beschreibt, in welchen Containerdiensten der Datenmodell-Instanzen platziert sind.
Dienst | Arten von Instanzen |
---|---|
Workspace | Enthält statische Modelle, die die 3D-Welt darstellen, insbesondere Teile der Welt, die keinem Spieler:ingehören.Du musst diese Instanzen nicht dynamisch erstellen, modifizieren oder zerstören, um sie zur Laufzeit akzeptabel zu machen, also ist es in Ordnung, sie hier zu lassen.: Es gibt auch eine leere Folder, zu der die Farmmodelle der Spieler zur Laufzeit hinzugefügt werden. |
Lighting | Atmosphärische und Beleuchtungseffekte. |
ReplicatedFirst | Enthält den kleinstmöglichen Unter集 von Instanzen, der zum Anzeigen des Ladebildschirms und zur Initialisierung des Spiels erforderlich ist.Je mehr Instanzen in ReplicatedFirst platziert werden, desto länger dauert die Wartezeit, bevor der Code in ReplicatedFirst ausführenwerden kann.:
|
ReplicatedStorage | Dient als Speichercontainer für alle Instanzen, für die auf dem Client und dem Server Zugriff erforderlich ist.:
|
ServerScriptService | Enthält einen Script , der als Einstiegsunkt für den gesamten Serverseiten-Code im Projekt dient. |
ServerStorage | Dient als Speichercontainer für alle Instanzen, die nicht auf den Client repliziert werden müssen.:
|
SoundService | Enthält die Sound Objekte, die für Soundeffekte im Spiel verwendet werden.Unter SoundService haben diese Sound Objekte keine Position und werden nicht im Platzsimuliert. |
Eingangspunkte
Die meisten Projekte organisieren Code innerhalb wiederverwendbarer ModuleScripts, die über die gesamte Codebasis importiert werden können.ModuleScripts sind wiederverwendbar, aber sie führen nicht besitzenaus; sie müssen von einem Script oder LocalScript importiert werden.Viele Roblox-Projekte werden eine große Anzahl von Script und LocalScript Objekten haben, die sich auf ein Verhalten oder ein bestimmtes System im Spiel beziehen und mehrere Eingangspunkte erzeugen.
Für das Pflanzen-Mikrospiel wird ein anderer Ansatz durch ein einzelnes LocalScript umgesetzt, das der Einstiegsplatz für den gesamten Codesist, und ein einzelnes Script, der der Einstiegsplatz für den gesamten Codesist.Der richtige Ansatz für Ihr Projekt hängt von Ihren Anforderungen ab, aber ein einziger Einstiegsplatz bietet eine größere Kontrolle über die Reihenfolge, in der Systeme ausgeführt werden.
Die folgenden Listen beschreiben die Abwägungen beider Ansätze:
- Ein einzelner Script und ein einzelner LocalScript deckt jeweils Server- und Client-Code ab.
- Größere Kontrolle über die Reihenfolge, in der verschiedene Systeme gestartet werden, da der gesamte Code aus einem einzigen Skript, das. PL: die Skriptsinitialisiert wird.
- Kann Objekte durch Referenz zwischen Systemen durchpassen.
Hochstufige Systemarchitektur
Die obersten Systeme im Projekt sind im Folgenden detailliert.Einige dieser Systeme sind deutlich komplexer als andere und in vielen Fällen wird ihre Funktionalität über eine Hierarchie anderer Klassen abstrahiert.

Jedes dieser Systeme ist ein "Singleton", da es eine nicht instanziierbare Klasse ist, die stattdessen vom relevanten Client oder Server Skript, das. PL: die Skriptsinitialisiert wird.Sie können später in diesem Leitfaden mehr über das Singleton-Muster lesen.
Server
Die folgenden Systeme sind mit dem Server verbunden.
System | Beschreibung |
---|---|
Netzwerk |
|
Spielerdatenserver |
|
Markt |
|
Kollisionsgрупppenmanager |
|
FarmManagerServer |
|
Spielerobjektkontainer |
|
TagSpieler |
|
FtueManagerServer |
|
Charaktererzeuger |
|
Client
Die folgenden Systeme sind mit dem Client verbunden.
System | Beschreibung |
---|---|
Netzwerk |
|
Spielerdatenclient |
|
Marktkunde |
|
Lokaler WalkJumpManager |
|
FarmManagerClient |
|
UI-Einstellung |
|
FtueManagerClient |
|
Charakterlauf |
|
Client-Server-Kommunikation
Die meisten Roblox-Erlebnisse beinhalten ein gewisses Element der Kommunikation zwischen dem Client und dem Server.Dies kann die Client-Anforderung umfassen, dass der Server eine bestimmte Aktion ausführt, und die Wiedergabe von Updates an den Client.
In diesem Projekt wird die Client-Server-Kommunikation so generisch wie möglich gehalten, indem die Verwendung von RemoteEvent und RemoteFunction Objekten begrenzt wird, um die Menge der speziellen Regeln zu verringern, die verfolgt werden müssen.Dieses Projekt verwendet die folgenden Methoden in der Reihenfolge der Präferenz:
- Replikation über das Spielerdatensystem.
- Replikation über Attributen.
- Replikation über Tags.
- Messaging direkt über das Netzwerk -Modul.
Replikation über das Spielerdatensystem
Das Spielerdatensystem ermöglicht es, Daten mit dem Spieler zu verknüpfen, der zwischen Speicherungen besteht.Dieses System bietet Replikation von Client auf Server und eine Reihe von APIs, die zur Abfrage von Daten und zum Abonnieren von Änderungen verwendet werden können, was es ideal macht, Änderungen im Spielerstatus vom Server auf den Client zu replizieren.
Zum Beispiel, anstatt einen benutzerdefinierten zu feuern, um dem Client mitzuteilen, wie viele Münzen er hat, kannst du das Folgende aufrufen und den Client über das Ereignis abonnieren lassen.
PlayerDataServer:setValue(player, "coins", 5)
Natürlich ist dies nur für die Server-zu-Client-Replikation und für Werte nützlich, die Sie zwischen Sitzungen bestehen lassen möchten, aber dies gilt für eine überraschende Anzahl von Fällen im Projekt, einschließlich:
- Die aktuelle FTUE-Stufe
- Das Inventar des Spieler:in
- Die Menge an Münzen, die der Spieler hat
- Der Zustand der Farm des Spieler:in
Replikation über Attribute
In Situationen, in denen der Server einen benutzerdefinierten Wert auf den Client replizieren muss, der spezifisch für einen bestimmten Instance ist, kannst du Attribute verwenden.Roblox repliziert automatisch Attributswerte, sodass du keine Code-Wege aufrechterhalten musst, um den Zustand mit einem Objekt zu replizieren.Ein weiterer Vorteil ist, dass diese Replikation neben der Instanz selbst stattfindet.
Dies ist besonders nützlich für Instanzen, die zur Laufzeit erstellt wurden, da Attributen, die auf einer neuen Instanz festgelegt werden, bevor sie dem Datenmodell zugewiesen werden, atomar mit der Instanz selbst repliziert werden.Dies umgeht die Notwendigkeit, Code zu schreiben, um zusätzliche Daten durch eine RemoteEvent oder StringValue zu "warten" zu replizieren.
Du kannst auch direkt Attribute aus dem Modelllesen, entweder vom Client oder vom Server, mit der Methode GetAttribute() , und dich über Änderungen mit der Methode GetAttributeChangedSignal() abonnieren.Im Pflanze-Projekt wird dieser Ansatz unter anderem verwendet, um den aktuellen Status von Pflanzen auf Clients zu replizieren.
Replikation über Tags
CollectionService lässt dich einen String-Tag auf ein Instance anwenden. Dies ist nützlich, um Instanzen zu kategorisieren und diese Kategorisierung auf den Client zu replizieren.
Zum Beispiel wird der Tag CanPlant auf dem Server angewendet, um dem Client mitzuteilen, dass ein bestimmter Topf in der Lage ist, eine Pflanze zu empfangen.
Nachricht direkt über Netzwerkmodul
Für Situationen, in denen keine der vorherigen Optionen anwendbar sind, kannst du benutzerdefinierte Netzanrufe über das Modul Netzwerk verwenden.Dies ist die einzige Option im Projekt, die die Kommunikation von Client zu Server ermöglicht und ist daher am nützlichsten für die Übermittlung von Clientanfragen und das Empfangen einer Serverantwort.
Pflanze verwendet direkte Netzanrufe für eine Vielzahl von Client-Anfragen, einschließlich:
- Eine Pflanze gießen
- Eine Saatgut pflanzen
- Einen Artikel kaufen
Der Nachteil mit diesem Ansatz ist, dass jede einzelne Nachricht eine maßgeschneiderte Konfiguration erfordert, die die Komplexität des Projekts erhöhen kann, obwohl dies wo immer möglich vermieden wurde, insbesondere für die Server-zu-Client-Kommunikation.
Klassen und Singletons
Klassen im Pflanzen-Projekt, wie Instanzen auf Roblox, können erstellt und zerstört werden.Die Klassen syntax ist von der idiomatischen Lua-Herangehensweise an objektorientierte Programmierung mit einer Reihe von Änderungen inspiriert, um strenges Typenprüfen zu ermöglichen.
Instanziierung
Viele Klassen im Projekt sind mit einer oder mehreren Instances verbunden.Objekte einer bestimmten Klasse werden mit einer new() erstellt, die mit der Art und Weise übereinstimmt, wie Instanzen in Roblox mit Instance.new().
Dieses Muster wird in der Regel für Objekte verwendet, bei denen die Klasse eine physische Repräsentation im Modellhat und die Klasse ihre Funktionalität erweitert.Ein gutes Beispiel ist , das ein Objekt zwischen zwei gegebenen Objekten erstellt und diese Anhänge so ausgerichtet hält, dass der Strahl immer nach oben zeigt.Diese Instanzen könnten aus einer vorgefertigten Version in ReplicatedStorage kopiert werden oder als Argument an new() übergeben und innerhalb des Objekts unter self gespeichert werden.
Korrespondierende Instanzen
Wie oben erwähnt, haben viele Klassen in diesem Projekt eine Datenmodellrepräsentation, eine Instanz, die der Klasse entspricht und von ihr manipuliert wird.
Anstatt diese Instanzen zu erstellen, wenn ein Klassenobjekt instanziiert wird, wählt der Code im Allgemeinen Clone() eine vorgefertigte Version des Instance unter ReplicatedStorage oder ServerStorage gespeichert.Obwohl es möglich wäre, die Eigenschaften dieser Instanzen zu serialisieren und sie von Grund auf neu in den new() zu erstellen, würde das dazu führen, dass das Bearbeiten der Objekte sehr aufwendig wird und sie für einen Leser schwieriger zu parsen sind.Zusätzlich ist das Klonen einer Instanz im Allgemeinen eine schnellere Operation als die Erstellung einer neuen Instanz und die Anpassung ihrer Eigenschaften zur Laufzeit.
Komposition
Obwohl Erbschaft in Luau mit Metatabellen möglich ist, wählt das Projekt stattdessen, dass Klassen sich durch Zusammensetzung erweitern können.Wenn Klassen durch Zusammensetzung kombiniert werden, wird das "Kind"-Objekt in der new() -Methode der Klasse instanziiert und als Mitglied unter self eingefügt.
Für ein Beispiel davon in Actionsiehe die CloseButton Klasse, die die Button Klasse einwickelt.
Aufbereiten
Ähnlich wie eine Instance mit der Methode Destroy() zerstört werden kann, können auch Klassen, die instanziiert werden können, zerstört werden.Die Zerstörermethode für Projektklassen ist destroy() mit einem kleinbuchstabigen d für camelCase Konsistenz über die Methoden der gesamten Codebasis, sowie um zwischen den Klassen des Projekts und Roblox-Instanzen zu unterscheiden.
Die Rolle der destroy()-Methode besteht darin, alle Instanzen zu zerstören, die vom Objekt erstellt wurden, alle Verbindungen zu trennen und auf alle Kindobjekte destroy() aufzurufen.Dies ist besonders wichtig für Verbindungen, weil Instanzen mit aktiven Verbindungen vom Luau-Garbage-Sammler nicht gereinigt werden, auch wenn keine Verweise auf die Instanz oder Verbindungen zur Instanz übrig bleiben.
Singletonen
Singletons, wie der Name vermuten lässt, sind Klassen, für die nur ein einziges Objekt jemals existieren kann.Sie sind das Äquivalent der Roblox-Dienste des Projekts.Anstatt ein Verweis auf das Singleton-Objekt zu speichern und es im Codesherumzupassen, nutzt Pflanze die Tatsache, dass es einen ModuleScript benötigt, um seinen zurückgegebenen Wert zu cache.Das bedeutet, dass die Anforderung des gleichen Singletons ModuleScript aus verschiedenen Orten konsistent das gleiche zurückgegebene Objekt liefert.Die einzige Ausnahme von dieser Regel wäre, wenn sich unterschiedliche Umgebungen (Client oder Server) auf den ModuleScript zugreifen würden.
Singletons werden von instabilen Klassen durch die Tatsache unterschieden, dass sie keine new() -Methode haben.Vielmehr wird das Objekt zusammen mit seinen Methoden und seinem Zustand direkt über die ModuleScript zurückgegeben.Da Singletons nicht instanziiert werden, wird die Syntax self nicht verwendet und Methoden werden stattdessen mit einem Punkt ( . ) anstelle eines Kolons aufgerufen ( : ).
Strekte Typ-Behauptung
Luau unterstützt schrittweises Tippen, was bedeutet, dass du frei bist, optionale Typdefinitionen zu einigen oder allen deinem Codeshinzuzufügen.In diesem Projekt wird strict Typprüfung für jedes Skript, das. PL: die Skriptsverwendet.Dies ist die am wenigsten zulässige Option für das Skriptanalyswerkzeug von Roblox und somit die wahrscheinlichste, um Typfehler vor der Laufzeit zu erfassen.
Typierte Klassen-Syntax
Der etablierte Ansatz zur Erstellung von Klassen in Lua ist gut dokumentiert, allerdings ist er nicht gut geeignet für starkes Luau-Typing.In Luau ist der einfachste Ansatz für das Erhalten der Klassenart die typeof() -Methode:
type ClassType = typeof(Class.new())
Das funktioniert, ist aber nicht sehr nützlich, wenn deine Klasse mit Werten initiiert wird, die nur zur Laufzeit existieren, zum Beispiel Player Objekte.Zusätzlich ist die Annahme, die in der idiomatischen Lua-Klassensyntax gemacht wird, dass die Erklärung einer Methode auf einer Klasse self immer eine Instanz dieser Klasse sein wird; das ist keine Annahme, die der Typ-Inferenz-Engine gemacht werden kann.
Um strengere Typ-Abstrichtung zu unterstützen, verwendet das Pflanze-Projekt eine Lösung, die sich in vielerlei Hinsicht von der idiomatischen Lua-Klassensyntax unterscheidet, von der einige nicht intuitiv erscheinen können:
- Die Definition von self wird dupliziert, sowohl in der Typdeklaration als auch im Konstruktor.Dies führt zu einer Instandhaltungsbelastung, aber Warnungen werden angezeigt, wenn die beiden Definitionen nicht mit einander übereinstimmen.
- Klassenmethoden werden mit einem Punkt deklariert, so kann self explizit erklärt werden, vom Typ ClassType zu sein.Methoden können immer noch mit einem Kolon wie erwartet aufgerufen werden.
--! streng
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
Typen nach logischen Schutzern ausgeben
Zur Zeit des Schreibens wird der Typ eines Werts nach einer Bedingungsabfrage nicht eingeschränkt.Zum Beispiel wird der Typ von optionalParameter durch die Wache unten nicht auf number eingeschränkt.
--! streng
local function foo(optionalParameter: number?)
if not optionalParameter then
return
end
print(optionalParameter + 1)
end
Um dies zu mindern, werden nach diesen Wachen neue Variablen erstellt, die explizit mit ihrem Typ gecastet werden.
--! streng
local function foo(optionalParameter: number?)
if not optionalParameter then
return
end
local parameter = optionalParameter :: number
print(parameter + 1)
end
Überquere Datenmodell-Hierarchien
In einigen Fällen muss die Codebasis die Datenmodell-Hierarchie eines Baumes von Objekten durchlaufen, die zur Laufzeit erstellt werden.Dies stellt eine interessante Herausforderung für die Typprüfung dar.Zu Zeiten der Schrift ist es nicht möglich, eine generische Datenmodell-Hierarchie als eingebenzu definieren.Als Ergebnis gibt es Fälle, in denen die einzige verfügbare Typinformation für eine Datenmodellstruktur die Art der obersten Instanz ist.
Ein Ansatz für diese Herausforderung ist, zu any zu casten und dann zu verfeinern. Zum Beispiel:
local function enableVendor(vendor: Model)
local zonePart: BasePart = (vendor :: any).ZonePart
end
Das Problem mit diesem Ansatz ist, dass er die Lesbarkeit beeinträchtigt.Stattdessen verwendet das Projekt ein generisches Modul namens getInstance, um Datenmodell-Hierarchien zu durchsuchen, die intern auf any zugehen.
local function enableVendor(vendor: Model)
local zonePart: BasePart = getInstance(vendor, "ZonePart")
end
Wenn sich das Verständnis der Typ-Engine für das Datenmodell weiterentwickelt, ist es möglich, dass Muster wie diese nicht mehr notwendig sind.
Benutzeroberfläche
Pflanze enthält eine Vielzahl von komplexen und einfachen 2D-Benutzeroberflächen.Dazu gehören nicht interaktive HUD-Elemente wie der Münzzähler und komplexe interaktive Menüs wie der kaufen.
UI-Ansatz
Du kannst Roblox UI grob mit dem HTML-DOM vergleichen, weil es eine Hierarchie von Objekten ist, die beschreibt, was der Benutzer sehen sollte.Ansätze zur Erstellung und Aktualisierung einer Roblox-Benutzeroberfläche sind grob in imperative und deklarative Praktiken unterteilt.
Ansatz | Vorteile und Nachteile |
---|---|
Verbesserung | Im imperativen Ansatz wird die UI wie jede andere Instanz-Hierarchie auf Roblox behandelt.Die UI-Struktur wird vor der Laufzeit in Studio erstellt und zum Modellhinzugefügt, typischerweise direkt in StarterGui.Dann manipuliert der Code zur Laufzeit bestimmte Teile der UI, um den Zustand zu reflektieren, den der Ersteller erfordert.: Dieser Ansatz kommt mit einigen Vorteilen.Du kannst die UI von Grund auf neu erstellen in Studio und sie im Modellspeichern.Dies ist ein einfaches und visuelles Bearbeitungserlebnis, das die Erstellung von UI beschleunigen kann.Da imperative UI-Code sich nur mit dem beschäftigt, was geändert werden muss, macht er auch einfache UI-Änderungen leicht zu implementieren.: Ein erheblicher Nachteil ist, dass, da imperative UI-Ansätze den Zustand manuell in Form von Transformationen implementieren müssen, komplexe Darstellungen des Zustands sehr schwer zu finden und zu debuggen sind.Es ist üblich, dass Fehler auftreten, wenn imperativer Codesentwickelt wird, insbesondere wenn der Zustand und die Benutzeroberfläche aufgrund mehrerer Updates in unerwarteter Reihenfolge desynchronisiert werden.: Eine weitere Herausforderung mit imperativen Ansätzen ist, dass es schwieriger ist, die UI in sinnvolle Komponenten aufzuteilen, die einmal deklariert und wiederverwendet werden können.Da der gesamte UI-Baum zur Bearbeitungszeit deklariert wird, können häufige Muster in mehreren Teilen des Modellwiederholt werden. |
Festlegend | Im deklarativen Ansatz werden die gewünschten Zustände von UI-Instanzen explizit deklariert, und die effiziente Umsetzung dieses Zustands wird durch Bibliotheken wie Roact oder Fusion abstraktiert.: Der Vorteil dieses Ansatzes ist die Umsetzung des Zustands wird trivial und Sie müssen nur beschreiben, wie Ihre UI aussehen soll.Das macht die Identifizierung und Lösung von Fehlern deutlich einfacher.: Der Hauptnachteil ist, dass der gesamte UI-Baum im Codesdeklariert werden muss.Bibliotheken wie Roact und Fusion haben eine Syntax, um dies zu erleichtern, aber es ist immer noch ein zeitaufwändiger Prozess und eine weniger intuitive Bearbeitungserfahrung beim Komponieren von UI. |
Pflanze verwendet einen imperativen Ansatz unter dem Gedanken, dass das Anzeigen der Transformationen direkt einen effektiveren Überblick darüber gibt, wie UI auf Roblox erstellt und manipuliert wird.Dies wäre mit einem deklarativen Ansatz nicht möglich.Einige wiederholte UI-Strukturen und -Logik werden auch in wiederverwendbare Komponenten abstrahiert, um einen gemeinsamen Fehler im imperativen UI-Design zu vermeiden.
Hochstufige Architektur

Schicht und Komponenten
In Pflanze sind alle UI-Strukturen entweder ein Layer oder ein Component.
- Layer wird als Oberstufen-Gruppierungssingel definiert, der vorfabrizierte UI-Strukturen in ReplicatedStorage einwickelt.Eine Schicht kann eine Reihe von Komponenten enthalten oder sie kann ihre eigene Logik vollständig kapseln.Beispiele für Schichten sind das Inventarmenü oder die Anzahl der Münzenindikatoren im Aufklappmenü.
- Component ist ein wiederverwendbares UI-Element.Wenn ein neues Komponentenobjekt instanziiert wird, kloniert es eine vorgefertigte Vorlage von ReplicatedStorage.Komponenten können selbst andere Komponenten enthalten.Beispiele für Komponenten sind eine generische Knopfklasse oder das Konzept einer Liste von Elementen.
Anzeigeverhalten anzeigen
Ein häufiges Problem der UI-Verwaltung ist die Anzeigengestaltung.Dieses Projekt hat eine Reihe von Menüs und HUD-Artikeln, von denen einige auf die Eingabe des Benutzers hören und die sorgfältige Verwaltung der Zeit, in der sie sichtbar oder aktiviert sind, erforderlich ist.
Pflanze greift dieses Problem mit ihrem UIHandler -System an, das festlegt, wann eine UI-Schicht sichtbar oder nicht sichtbar sein soll.Alle Benutzeroberflächenschichten im Spiel werden als HUD oder Menu kategorisiert und ihre Sichtbarkeit wird durch die folgenden Regeln verwaltet:
- Der aktivierte Zustand von Menu und HUD Schichten kann umgeschaltet werden.
- Aktivierte HUD Schichten werden nur angezeigt, wenn keine Menu Schichten aktiviert sind.
- Aktivierte Menu Schichten werden in einem Stapel gespeichert, und nur eine Menu Schicht ist gleichzeitig sichtbar.Wenn eine Menu Schicht aktiviert ist, wird sie an die Vorderseite des Stacks eingefügt und angezeigt.Wenn eine Menu Schicht deaktiviert wird, wird sie vom Stapel entfernt und die nächste aktivierte Menu Schicht in der Warteschlange wird angezeigt.
Dieser Ansatz ist intuitiv, weil er es ermöglicht, Menüs mit Geschichte zu navigieren.Wenn ein Menü aus einem anderen Menü geöffnet wird, wird das Schließen des neuen Menüs das alte Menü erneut anzeigen.
UI-Schichten singletons registrieren sich mit dem UIHandler und werden mit einem Signal bereitgestellt, das ausgelöst wird, wenn seine Sichtbarkeit sich ändern sollte.
Weiterlesen
Aus dieser gründlichen Übersicht des Pflanzen-Projekts möchten Sie vielleicht die folgenden Leitfäden erkunden, die detaillierter in verwandten Konzepten und Themen einsteigen.
- Client-Server-Modell — Ein Überblick über das Client-Server-Modell in Roblox.
- Remote-Ereignisse und Rückrufe — Alles über Remote-Netzwerkereignisse und Rückrufe für die Kommunikation über die Client-Server-Grenze.
- UI — Details zu Benutzeroberflächenobjekten und Design auf Roblox.