Projekt referencyjny rośliny

*Ta zawartość została przetłumaczona przy użyciu narzędzi AI (w wersji beta) i może zawierać błędy. Aby wyświetlić tę stronę w języku angielskim, kliknij tutaj.

Planta to doświadczenie referencyjne, w którym gracze sadzą i podlewają nasiona, tak aby później mogli zebrać i sprzedać powstałe rośliny.

Plant project banner

Projekt skupia się na powszechnych przypadkach użycia, które możesz napotkać podczas opracowywania doświadczenia na Roblox.Gdzie to mające zastosowanie, znajdziesz notatki o kompromisach, wymianach i uzasadnieniu różnych wyborów implementacji, abyś mógł podjąć najlepszą decyzję dla własnych doświadczeń.

Zdobądź plik

  1. Przejdź do strony doświadczenia Rośliny.
  2. Kliknij przycisk i Edytuj w Studio .

Użyj przypadków

Roślinka obejmuje następujące przypadki użycia:

  • Trwałość danych sesji i danych gracza
  • Zarządzanie widokiem UI
  • Sieć klient-serwer
  • Pierwsze doświadczenie użytkownika (FTUE)
  • Zakupy waluty miękkiej i twardej

Ponadto ten projekt rozwiązuje węższe zestawy problemów, które są stosowane do wielu doświadczeń, w tym:

  • Dostosowanie obszaru na miejscu, które jest powiązane z graczem
  • Zarządzanie prędkością ruchu postaci gracza
  • Tworzenie obiektu, który podąża za znakami
  • Wykrywanie, w jakiej części świata jest postać

Zauważ, że istnieje kilka przypadków użycia w tym doświadczeniu, które są zbyt małe, zbyt niszowe lub nie pokazują rozwiązania do interesującego wyzwania projektowego; nie są one pokryte.

Struktura projektu

Pierwszą decyzją przy tworzeniu doświadczenia jest decyzja o tym, jak zorganizować projekt , który głównie obejmuje to, gdzie umieścić konkretne instancje w modelu danych i jak zorganizować i zstrukturyzować punkty wejścia dla kodu klienta i serwera.

Model danych

Poniższa tabela opisuje, do jakich usług kontenerowych w instancjach modelu danych są umieszczone.

UsługaRodzaje instancji
Workspace

Zawiera statyczne modele reprezentujące świat 3D, szczególnie części świata, które nie należą do żadnego gracza.Nie musisz dynamicznie tworzyć, modyfikować lub niszczyć tych instancji podczas uruchamiania, więc akceptowane jest pozostawienie ich tutaj.:

Istnieje również puste Folder , do którego dodane zostaną modele farmy graczy podczas uruchamiania.

Lighting

Efekty atmosferyczne i oświetleniowe.

ReplicatedFirst

Zawiera najmniejszy możliwy podzbiór instancji potrzebny do wyświetlenia ekranu ładowania i inicjalizacji gra.Im więcej instancji zostanie umieszczonych w ReplicatedFirst, tym dłużej będzie czekać na ich replikację, zanim kod w ReplicatedFirst może zostać uruchomiony.:

  • W katalogu Instancje znajduje się interfejs GUI ładowania.:
  • W katalogu Źródło znajduje się kod ekranu ładowania i kod potrzebny do oczekiwania na załadowanie reszty gry.Punkt wejścia start LocalScript jest punktem wejścia dla całego kodu strony klienta w projekcie.
ReplicatedStorage

Służy jako pojemnik do przechowywania dla wszystkich instancji, do których jest wymagany dostęp zarówno na klientzie, jak i na serwerze.:

  • W folderze Zależności istnieją niektóre biblioteki stron trzecich używane przez projekt.: W katalogu Instancje istnieje szeroki zakres gotowych instancji używanych przez różne klasy w gra.: W katalogu źródła istnieje cały kod nie wymagany do procesu ładowania, który musi być dostępny zarówno z klienta, jak i serwera.
ServerScriptService

Zawiera Script służący jako punkt wejścia dla całego kodu stron serwera w projekcie.

ServerStorage

Służy jako pojemnik do przechowywania dla wszystkich instancji, które nie muszą być replikowane do klienta.:

W folderze Instancje istnieje model szablonu Farm .Kopia tego jest umieszczana w gdy gracz dołącza do gry, gdzie zostanie powielona dla wszystkich graczy.: W katalogu źródła istnieje cały kod, który jest wyłączny dla serwera.

SoundService

Zawiera obiekty Sound używane do efektów dźwiękowych w gra.Poniżej SoundService , te obiekty Sound nie mają pozycji i nie są symulowane w przestrzeni 3D.

Punkty wejścia

Większość projektów organizuje kod wewnątrz ponownie używalnego ModuleScripts, który można zaimportować na całą bazę kodu.ModuleScripts są ponownie używalne, ale nie wykonują ich posiadać; muszą być zaimportowane przez Script lub LocalScript .Wiele projektów Roblox będzie miało dużą liczbę Script i LocalScript obiektów, każdy z nich odnoszący się do zachowania lub konkretnego systemu w gra, tworząc wiele punktów wejścia.

W przypadku mikrogry Rośliny, różne podejście jest wdrażane za pomocą pojedynczego >, który jest punktem wejścia dla wszystkiego kodu klienta, oraz pojedynczego >, który jest punktem wejścia dla wszystkiego kodu serwera.Poprawny podejście do twojego projektu zależy od twoich wymagań, ale pojedyncze miejsce wejścia zapewnia większą kontrolę nad kolejnością wykonywania systemów.

Następujące listy opisują wady obu podejść:

  • Jeden Script i jeden LocalScript pokrywa kod serwera i klienta odpowiednio.
  • Większa kontrola nad kolejnością uruchamiania różnych systemów, ponieważ cały kod jest inicjalizowany z pojedynczego skryptu.
  • Można przekazywać obiekty przez odniesienie między systemami.

Architektura systemu wysokiego poziomu

Systemy najwyższego poziomu w projekcie są szczegółowo opisane poniżej.Niektóre z tych systemów są znacznie bardziej skomplikowane niż inne, a w wielu przypadkach ich funkcjonalność jest uproszczona na poziomie hierarchii innych klas.

Plant project systems architecture diagram

Każdy z tych systemów jest "singletonem", ponieważ jest to niezinstancjonalna klasa, która zamiast tego jest inicjalizowana przez odpowiedni klient lub serwer start skrypt.Możesz przeczytać więcej o wzorcu singleton później w tym przewodniku.

Serwer

Następujące systemy są związane z serwerem.

SystemOpis
Sieć
  • Tworzy wszystkie RemoteEvent i RemoteFunction instancje.:
  • Pokazuje metody do wysyłania i odbierania wiadomości od klienta.:
  • Walidacja typu dla argumentów otrzymanych od klienta podczas uruchamiania.
Serwer danych gracza
  • Zapisuje i ładowuje trwałe dane gracza za pomocą DataStoreService .:
  • Przechowuje dane gracza w pamięci i replikuje mutacje do klienta.:
  • Pokazuje sygnały i metody do subskrybowania, zapytania i aktualizowania danych odtwarzacza.
Rynek
  • Obsługuje miękkie transakcje walutowe z klienta. >
  • Ujawnia metodę do sprzedaży zebranych roślin. >
Menadżer grupy kolizji
  • Przydziela modele postaci gracza do grup kolizyjnych.:
  • Konfiguruje grupy kolizji, aby postacie graczy nie mogły zderzać się z wagonami roślinnymi.
Serwer menedżera farmy
  • Otwiera model farmy gracza z jego danych gracza, gdy dołącza do gry.:
  • Usuwa model farmy, gdy gracz odchodzi.:
  • Aktualizuje dane gracza, gdy zmieniona jest farma gracza.:
  • Ujawnia metodę dostępu do klasy Farm związanej z danym graczem.
Kontener obiektów gracza
  • Tworzy różne obiekty związane z czasem trwania gracza i zapewnia metodę do odzyskania ich.
Gracze tagowe
Serwer Menadżera Ftue
  • Podczas FTUE wykonuje każdy etap i czeka, aż się zakończy.
Spawner postaci
  • Odradza postacie, gdy umierają.Zauważ, że Players.CharacterAutoLoads został wyłączony, aby spawnowanie zostało wstrzymane, dopóki nie zostaną załadowane dane gracza.

Klienci

Następujące systemy są związane z klientem.

SystemOpis
Sieć
  • Czeka, aż serwer stworzy wszystkie RemoteEvent i RemoteFunction instancje.:
  • Pokazuje metody do wysyłania i odbierania wiadomości z i do serwera.:
  • Wymusza walidację typu parametru czasu wykonania.:
  • Wykonuje pcall() na zdalnych funkcjach.
Klient danych gracza
  • Przechowuje dane lokalnego gracza w pamięci.:
  • Ujawnia metody i sygnały do zapytania i subskrybowania zmian w danych gracza.
Klient rynkowy
  • Ujawnia metodę, aby poprosić serwer o zakup walutaza walutę miękką.
Lokalny skok menedżera
  • Ujawnia metody do modyfikacji WalkSpeed lub JumpHeight postaci za pomocą mnożników, aby uniknąć konfliktów podczas modyfikowania tych wartości z wielu miejsc.
Klient FarmManager
  • Słucha specyficznych tagów CollectionService zostających zastosowanych do instancji i tworzy aplikację "komponentów", które dodają zachowanie do tych instancji.Komponent odnosi się do klasy, która jest tworzona, gdy dodany zostanie tag CollectionService i jest niszczony, gdy jest usuwany; są one używane do okien CTA na farmie i różnych klas teleportujących stan farmy do gracza.
Konfiguracja interfejsu
  • Inicjalizuje wszystkie warstwy interfejsu.:
  • Konfiguruje pewne warstwy, które będą widoczne tylko w fizycznych sekcjach świata gry.:
  • Podłącz specjalny efekt kamery dla czasu, gdy włączone są menu.
Klient Menedżera Ftue
  • Konfiguruje etapy FTUE na klientzie.
Bieg postaci
  • Korzysta z LocalWalkJumpManager , aby zwiększyć WalkSpeed, gdy postać gracza jest poza jego farmą.

Komunikacja klient-serwer

Większość doświadczeń Roblox obejmuje pewien element komunikacji między klientem a serwerem.Może to obejmować wniosek klienta o wykonanie przez serwer pewnej akcji i replikowanie aktualizacji do klienta.

W tym projekcie komunikacja klient-serwer jest utrzymywana tak ogólna, jak to możliwe, ograniczając użycie obiektów RemoteEvent i RemoteFunction, aby zmniejszyć ilość specjalnych zasad, które należy śledzić.Ten projekt wykorzystuje następujące metody, w kolejności preferencji:

  • Replikacja za pośrednictwem systemu danych gracza .
  • Replikacja za pomocą atraktorów.
  • Replikacja za pomocą tagów ..
  • Wysyłanie wiadomości bezpośrednio za pośrednictwem modułu Sieć.

Replikacja za pośrednictwem systemu danych gracza

System danych odtwarzacza pozwala na powiązanie danych z graczem, który utrzymuje się między sesjami zapisu .System ten zapewnia replikację od klienta do serwera i zestaw API, które można wykorzystać do zapytania o dane i subskrybowania zmian, co czyni go idealnym do replikowania zmian w stanie gracza z serwera na klient.

Na przykład, zamiast wystrzelić niestandardowy UpdateCoins``Class.RemoteEvent do powiedzenia klientowi, ile monet ma, możesz wezwać następujący i pozwolić mu subskrybować go za pomocą wydarzenia PlayerDataClient.updated.


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

Oczywiście, jest to przydatne tylko w przypadku replikacji od serwera do klienta i dla wartości, które chcesz utrzymać między sesjami, ale dotyczy to zaskakującej liczby przypadków w projekcie, w tym:

  • Obecny etap FTUE
  • wyposażeniegracza
  • Ilość monet, które posiada gracz
  • Stan farmy gracza

Replikacja za pomocą atrybutów

W sytuacjach, w których serwer musi odtworzyć niestandardową wartość dla klienta, który jest specyficzny dla danego Instance, możesz użyć atrybutów.Roblox automatycznie replikuje wartości atrybutów, więc nie musisz utrzymywać żadnych ścieżek kodu, aby odtworzyć stan związany z obiektem.Kolejną zaletą jest to, że ta replikacja ma miejsce obok samej instancji.

Jest to szczególnie przydatne w przypadku instancji tworzonych podczas uruchamiania, ponieważ atrybuty ustawione na nowej instancji, zanim zostaną przypisane do modelu danych, będą się replikować atomowo z samą instancją.Unika to potrzeby pisania kodu, aby "poczekać" na dodatkowe dane, które zostaną replikowane za pomocą RemoteEvent lub StringValue.

Możesz również bezpośrednio odczytywać atrybuty z modelu danych, z klienta lub serwera, za pomocą metody GetAttribute() i subskrybować zmiany za pomocą metody GetAttributeChangedSignal().W projekcie Roślinka, podejście to jest stosowane między innymi do replikowania obecnego stanu roślin dla klientów.

Replikacja za pomocą tagów

CollectionService pozwala ci zastosować tag ciągu do Instance . Jest to przydatne do kategoryzacji instancji i replikowania tej kategoryzacji do klienta.

Na przykład tag CanPlant jest stosowany na serwerze, aby poinformować klienta, że dany pojemnik jest w stanie otrzymać roślinę.

Wiadomość bezpośrednio za pomocą modułu sieciowego

W przypadkach, gdy żadna z poprzednich opcji nie ma zastosowania, możesz używać niestandardowych połączeń sieciowych za pośrednictwem modułu Sieć .Jest to jedyna opcja w projekcie, która umożliwia komunikację klienta z serwerem i jest zatem najbardziej przydatna do przesyłania żądań klienta i otrzymywania odpowiedzi serwera.

Roślę używa bezpośrednich połączeń sieciowych dla różnych żądań klienta, w tym:

  • Podlewanie rośliny
  • Sadzenie nasiona
  • Zakup przedmiotu

Wadą takiego podejścia jest to, że każda indywidualna wiadomość wymaga pewnej niestandardowej konfiguracji, która może zwiększyć złożoność projektu, choć unikano tego, gdzie to możliwe, szczególnie w przypadku komunikacji serwer-klient.

Klasy i jednostki klasowe

Klasy w projekcie Planta mogą być tworzone i niszczone, tak jak instancje na Roblox.Jego klasowa sintaksja jest inspirowana idiomatycznym podejściem Lua do programowania obiektowego z szeregiem zmian, aby umożliwić surową weryfikację typu poprzez wsparcie.

Inicjalizacja

Wiele klas w projekcie jest powiązanych z jednym lub więcej Instances .Obiekty danej klasy są tworzone za pomocą metody new(), zgodnie z tym, jak instancje są tworzone w Roblox za pomocą Instance.new().

Wzór ten jest zwykle używany do obiektów, w których klasa ma fizyczną reprezentację w modelu danych, a klasa rozszerza swoją funkcjonalność.Dobrym przykładem jest , który tworzy obiekt między dwoma podanymi obiektami i utrzymuje te załączniki skierowane w górę, tak aby promień zawsze był skierowany w górę.Te instancje mogą być sklonowane z wersji gotowej w ReplicatedStorage lub przekazane do new() jako argument i przechowywane wewnątrz obiektu pod self .

Odpowiednie instancje

Jak wspomniano powyżej, wiele klas w tym projekcie ma reprezentację modelu danych, instancję, która odpowiada klasie i jest przez nią manipulowana.

Zamiast tworzyć te instancje, gdy obiekt klasy jest instancjalizowany, kod ogólnie decyduje się na wersję gotową przechowywaną pod lub .Chociaż możliwe byłoby serjalizowanie właściwości tych instancji i tworzenie ich od podstaw w funkcjach klasy new(), dokonanie tego sprawiłoby, że edytowanie obiektów będzie bardzo uciążliwe i uczyni je trudniejszymi do odczytania dla czytelnika.Ponadto klonowanie instancji jest ogólnie szybszą operacją niż tworzenie nowej instancji i dostosowywanie jej właściwości podczas uruchamiania.

Skład

Chociaż dziedziczenie jest możliwe w Luau za pomocą metatablic, projekt decyduje się zamiast tego pozwolić klasom rozszerzać się wzajemnie za pomocą kompozycji .Podczas łączenia klas za pomocą kompozycji obiekt "dziecko" jest instancjalizowany w metodzie klasy new() i jest włączany jako członek pod self .

Aby zobaczyć przykład tego w akcji, zobacz klasę CloseButton, która owija klasę Button.

Oczyszczenie

Podobnie do sposobu, w jaki można zniszczyć Instance z metodą Destroy(), klasy, które można instancjować, również mogą zostać zniszczone.Metoda dekstruktora dla klas projektowych jest destroy() z małą literą d dla camelCase spójności między metodami kodu źródłowego, a także do odróżnienia klas projektowych od instancji Roblox.

Rola metody destroy() jest niszczenie każdej instancji stworzonej przez obiekt, odłączanie wszelkich połączeń i wezwanie destroy() na każdym dziecięcym obiekcie.Jest to szczególnie ważne dla połączeń, ponieważ instancje z aktywnymi połączeniami nie są czyszczone przez zbieracza śmieci Luau, nawet jeśli nie pozostają żadne odniesienia do instancji ani połączenia do instancji.

Singletony

Singletony, jak nazwa wskazuje, są klasami, dla których może istnieć tylko jeden obiekt.Są odpowiednikiem usług Roblox'a dla projektu.Zamiast przechowywać odniesienie do obiektu jedynkowego i przekazywać je w kodzie Luau, Roślina korzysta z faktu, że wymaganie ModuleScript przechowuje jego zwróconą wartość.Oznacza to, że wymaganie tego samego singletu ModuleScript z różnych miejsc konsekwentnie dostarcza ten sam zwracany obiekt.Jedynym wyjątkiem od tej zasady byłoby, gdyby różne środowiska (klient lub serwer) uzyskały dostęp do ModuleScript.

Singletony są odróżniane od klas niestabilnych przez to, że nie mają metody new().Raczej obiekt wraz z jego metodami i stanem jest zwracany bezpośrednio za pośrednictwem ModuleScript.Ponieważ singletony nie są instancjalizowane, nie jest używana sintaks self i metody są zamiast tego nazywane za pomocą kropki ( . ), a nie kolonki ( : ).

Surowa inferencja typu

Luau wspiera stopniowe pisanie, co oznacza, że możesz dodać opcjonalne definicje typów do niektórych lub wszystkich kodów.W tym projekcie, strict kontrola typu jest używana dla każdego skryptu.Jest to najmniej restrykcyjna opcja dla narzędzia analizy skryptów Roblox i zatem najbardziej prawdopodobna, aby złapać błędy typu przed uruchomieniem.

Typowana sintaks klasy

Ustanowiony sposób tworzenia klas w Lua jest dobrze udokumentowany, jednak nie jest odpowiedni do silnego typowania Luau.W Luau najprostszym podejściem do uzyskania typu klasy jest metoda typeof():


type ClassType = typeof(Class.new())

Działa to, ale nie jest to bardzo przydatne, gdy klasa jest inicjowana za pomocą wartości, które istnieją tylko podczas uruchamiania, na przykład Player obiekty.Ponadto założenie użyte w idiomatycznej klasowej sintaksie Lua jest takie, że deklarowanie metody na klasie self zawsze będzie instancją tej klasy; nie jest to założenie, które może zrobić silnik typowania.

Aby wspierać ścisłą inferencję typu, projekt Planta używa rozwiązania, które różni się od idiomatycznej sygnatury klasy Lua na wiele sposobów, z których niektóre mogą wydawać się niedostępne:

  • Definicja self jest powielona, zarówno w deklaracji typu, jak i w konstruktorze.Wprowadza to obciążenie utrzymywania, ale ostrzeżenia zostaną oznaczone, jeśli dwie definicje wpadną w rozbieżność z siebie.
  • Metody klasy są deklarowane za pomocą kropki, więc self można wyraźnie deklarować jako typ ClassType.Metody nadal można wezwać za pomocą kolonki, jak oczekiwano.

--!ściśle
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

Rzucaj typy po strażnikach logicznych

W momencie pisania typ wartości nie jest ograniczany po wypowiedzeniu warunkowego oświadczenia strażnika.Na przykład, po śledzeniu strażnika poniżej, typ optionalParameter nie jest ograniczony do number.


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

Aby złagodzić to, nowe zmienne są tworzone po tych strażnikach z ich typem wyraźnie obsługiwanym.


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

Przeszukaj hierarchie modelu danych

W niektórych przypadkach kod bazowy musi przejść przez hierarchię modelu danych drzewa obiektów, które są tworzone podczas uruchamiania.Stwarza to interesujące wyzwanie dla weryfikacji typu.W momencie pisania nie jest możliwe określenie hierarchii ogólnego modelu danych jako wpisywać.W wynikistnieją przypadki, w których jedyną dostępną informacją typu dla struktury modelu danych jest rodzaj instancji najwyższego poziomu.

Jednym ze sposobów na to wyzwanie jest rzucenie do any i następnie dopracowanie. Na przykład:


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

Problem z tym podejściem polega na tym, że wpływa na czytelność.Zamiast tego projekt używa ogólnego modułu o nazwie getInstance do przeglądania hierarchii modelu danych, które przekazują do any wewnętrznie.


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

W miarę rozwoju zrozumienia modelu danych przez silnik typu możliwe jest, że wzory takie jak ten nie będą już potrzebne.

Interfejs użytkownika

Roślina obejmuje różnorodne skomplikowane i proste interfejsy użytkownika 2D.Obejmują one nieinteraktywne przedstawienia informacji (HUD), takie jak licznik monet i skomplikowane interaktywne menu, takie jak robić zakupy.

Podejście UI

Możesz luźno porównać interfejs użytkownika Roblox z HTML DOM, ponieważ jest to hierarchia obiektów, które opisują to, co użytkownik powinien widzieć.Podejścia do tworzenia i aktualizowania interfejsu użytkownika Roblox są szeroko podzielone na imperatywne i deklaratywne praktyki.

PodejścieZalety i wady
Imperatywny

W podejściu imperatywnym interfejs użytkownika jest traktowany jak każda inna hierarchia instancji na Roblox.Struktura interfejsu użytkownika jest tworzona przed uruchomieniem w Studio i dodawana do modelu danych, zwykle bezpośrednio w StarterGui.Następnie, podczas uruchamiania, kod manipuluje konkretnymi częściami interfejsu, aby odzwierciedlić stan, który wymaga twórca.:

Taki podejście ma pewne zalety.Możesz tworzyć interfejs użytkownika od podstaw w Studio i przechowywać go w modelu danych.Jest to proste i wizualne doświadczenie edytowania, które może przyspieszyć dziełointerfejsu.Ponieważ kod imperatywny interfejsu użytkownika dotyczy tylko tego, co należy zmienić, ułatwia to również wdrażanie prostych zmian interfejsu użytkownika.:

Dużą wadą jest to, że ponieważ podejścia imperatywne do interfejsu użytkownika wymagają, aby stan był ręcznie wdrożony w formie transformacji, skomplikowane reprezentacje stanu mogą być bardzo trudne do znalezienia i debugowania.Wspólne jest pojawianie się błędów podczas opracowywania kodu imperatywnego interfejsu użytkownika, szczególnie w przypadku, gdy stan i interfejs użytkownika stają się niezsynchronizowane z powodu wielu aktualizacji interakujących w nieoczekiwanej kolejności.:

Innym wyzwaniem z podejściami imperatywnymi jest to, że trudniej jest rozbić interfejs użytkownika na znaczące komponenty, które można jeden raz zadeklarować i ponownie wykorzystać.Ponieważ całe drzewo UI jest deklarowane w czasie edycji, powszechne wzory mogą być powtarzane w wielu częściach modelu danych.

Deklaratywne

W podejściu deklaratywnym, pożądany stan instancji interfejsu jest deklarowany wyraźnie, a skuteczna realizacja tego stanu jest odizolowana przez biblioteki takie jak Roact lub Fusion.:

Zaletą tego podejścia jest to, że implementacja stanu staje się trywialna i musisz tylko opisać, jak chcesz, aby twoja interfejs wyglądał.Ułatwia to znacznie identyfikowanie i rozwiązywanie błędów.:

Główną wadą jest konieczność deklarowania całego drzewa UI w kodzie.Biblioteki takie jak Roact i Fusion mają składnię, aby ułatwić to zadanie, ale nadal jest to czasochronny proces i mniej intuicyjne doświadczenie edytowania przy komponowaniu interfejsu.

Roślina używa podejścia imperatywnego w ramach pojęcia, że pokazanie transformacji bezpośrednio daje bardziej efektywny przegląd sposobu tworzenia i manipulowania interfezami na Roblox.Nie byłoby to możliwe przy podejściu deklaratywnym.Niektóre powtarzalne struktury i logika interfejsu użytkownika są również uproszczone do ponownie używalnych komponentów, aby uniknąć wspólnego błędu w projektowaniu interfejsu użytkownika w trybie imperatywnym.

Architektura wysokiego poziomu

Plant project UI architecture diagram

Warstwa i komponenty

W roślinie wszystkie struktury interfejsu są albo Layer lub albo Component.

  • Layer jest określony jako singiel grupowania najwyższego poziomu, który owija gotowe struktury UI w ReplicatedStorage .Warstwa może zawierać wiele komponentów lub może całkowicie owinąć własną logikę.Przykłady warstw to menu zapasów lub liczba wskaźników monet w oknie podglądu.
  • Component jest wielokrotnie używalnym elementem interfejsu.Gdy zostanie zainicjowany nowy obiekt komponentu, klonuje on gotowy szablon z ReplicatedStorage.Komponenty mogą w sobie zawierać inne komponenty.Przykłady komponentów to ogólna klasa przycisków lub koncepcja listy przedmiotów.

Widok obsługi

Pospolity problem zarządzania interfejsem użytkownika to obsługa widoków.Ten projekt ma wiele menu i przedmiotów HUD, z których niektóre słuchają wejścia użytkownika, a wymagane jest staranne zarządzanie tym, kiedy są widoczne lub włączone.

Roślina podejmuje ten problem ze swoim systemem UIHandler , który zarządza tym, kiedy warstwa UI powinna lub nie powinna być widoczna.Wszystkie warstwy interfejsu w grze są kategoryzowane jako HUD lub Menu i ich widoczność jest zarządzana przez następujące zasady:

  • Stan włączony Menu i HUD poziomów może być przełączony.
  • Włączone warstwy HUD są pokazywane tylko wtedy, gdy nie są włączone warstwy Menu.
  • Włączone warstwy Menu są przechowywane w stosie, a tylko jedna warstwa Menu jest widoczna jednocześnie.Gdy warstwa Menu jest włączona, jest wstawiona na przód stosu i pokazana.Kiedy warstwa Menu jest wyłączona, jest usuwana z stosu, a następna włączona warstwa Menu jest wyświetlana w kolejce.

Ta metoda jest intuicyjna, ponieważ pozwala na nawigowanie menu za pomocą historii.Jeśli jedno menu jest otwarte z innego menu, zamknięcie nowego menu wyświetli ponownie stare menu.

Singlony poziomu interfejsu rejestrują się z UIHandler i otrzymują sygnał, który włącza się, gdy jego widoczność ma się zmienić.

Dalsze czytanie

Z tego dogłębnego przeglądu projektu Planta, możesz chcieć zbadać następujące przewodniki, które idą dalej w głąb związanych koncepcji i tematów.

  • Model klient-serwer — Przeglad modelu klient-serwer w Roblox.
  • Luau — Szczegóły na temat Luau , języka programowania stworzonego przez Roblox pochodzącego z Lua 5.1.
  • Wydarzenia zdalne i wezwania — Wszystko o zdalnych wydarzeniach sieciowych i wezwaniach do komunikacji między granicą klienta-serwera.
  • Interfejs użytkownika — Szczegóły na temat obiektów interfejsu użytkownika i projektowania na Roblox.