Wykonując ten krok w samouczku Próba czasu: Pogoń za pizzą (Time Trial: Pizza Pursuit), nauczysz się zarządzać wynikiem, gdy gracz odbiera i dostarcza przedmioty, a także aktualizować UI w celu wyświetlenia wyników. Aby dowiedzieć się więcej o tworzeniu UI w grze w Verse, patrz: Tworzenie UI w grze.
Menedżer wyników będzie śledzić i wyświetlać następujące wartości:
Łączna liczba punktów: Oznacza całkowitą liczbę punktów zdobytych przez gracza w grze.
Liczba punktów oczekujących: Oznacza punkty, jakie gracz zgromadził za bieżący zbiór odebranych przedmiotów.
Poziom odbioru: Oznacza bieżący poziom odbioru.
Tworzenie UI
Aby utworzyć UI menedżera wyników w Verse, wykonaj następujące instrukcje:
Utwórz nowy pusty plik Verse i nadaj mu nazwę score_manager.verse.
Utwórz nową klasę o nazwie
score_manageri dodaj do niej następujące pola:Opcjonalny element
agento nazwieMaybePlayerdo przechowywania odwołania do gracza.MaybePlayer<internal> : ?agent = falseOpcjonalny element
player_uio nazwieMaybePlayerUIdo przechowywania odwołania do UI gracza.MaybePlayerUI<internal> : ?player_ui = falseElement
score_manager_devicedo przechowywania odwołania dla urządzenia menedżera wyniku, wokół którego utworzono tę klasę. (Pamiętaj, że nie jest to odwołanie edytowalne, ponieważ musi być połączone z urządzeniemgame_coordinator_deviceutworzonym w Verse.ScoreManagerDevice<internal> : score_manager_device = score_manager_device{}Zmienna z liczbą całkowitą o nazwie
TotalGameScorereprezentująca wszystkie punkty zdobyte przez gracza w trakcie całej gry.var TotalGameScore<private> : int = 0Zmienna z liczbą całkowitą o nazwie
PendingScorereprezentująca punkty, jakie gracz ma w tej chwili zgromadzone za dany zestaw odebranych przedmiotów.var PendingScore<private> : int = 0Zmienna z liczbą całkowitą o nazwie
PickupLevelreprezentująca bieżący poziom odbioru.var PickupLevel<private> : int = 0
Utworzona definicja klasy score_manager powinna wyglądać następująco:
score_manager := class: MaybePlayer<internal> : ?agent = false MaybePlayerUI<internal> : ?player_ui = false ScoreManagerDevice<internal> : score_manager_device = score_manager_device{} var TotalGameScore<private> : int = 0 var PendingScore<private> : int = 0 var PickupLevel<private> : int = 0Utwórz UI przy pierwszym utworzeniu klasy. Można to zrobić, dodając do definicji klasy wyrażenie
block, które będzie wykonywane przy każdym utworzeniu instancji klasy. Dodaj następujące zmienne w celu wygenerowania UI:Zmienna
canvaso nazwieCanvaszawierająca specyfikatorinternaldo przechowywania niestandardowego widżetu kanwy.var Canvas<internal> : canvas = canvas{}Zmienna
text_blocko nazwieTotalGameScoreWidgetzawierająca specyfikatorinternaldo przechowywania widżetu tekstu w celu wyświetlenia wszystkich punktów zdobytych przez gracza w trakcie całej gry reprezentowanych przez zmiennąTotalGameScore. Ustaw domyślny kolor tekstu bloku tekstu na biały.TotalGameScoreWidget<internal> : text_block = text_block{DefaultTextColor := NamedColors.White}Zmienna
text_blocko nazwiePendingScoreWidgetzawierająca specyfikatorinternaldo przechowywania widżetu tekstu w celu wyświetlenia punktów, jakie gracz ma obecnie zgromadzone za dany zbiór odebranych przedmiotów, reprezentowanych przez zmiennąPendingScore. Ustaw domyślny kolor tekstu bloku tekstu na biały.PendingScoreWidget<internal> : text_block = text_block{}Zmienna
text_blocko nazwiePickupLevelWidgetzawierająca specyfikatorinternaldo przechowywania widżetu tekstu w celu wyświetlenia bieżącego poziomu odbioru reprezentowanego przez zmiennąPickupLevel. Ustaw domyślny kolor tekstu bloku tekstu na biały.PickupLevelWidget<internal> : text_block = text_block{}Funkcja zwracająca wynik
messageo nazwieTotalGameScoreTexttworząca możliwy do zlokalizowania tekst, który może być wyświetlany w UI dla ogólnej liczby punktów zdobytych przez gracza w grze.TotalGameScoreText<localizes>(CurrentTotalGameScore : int) : message = "Total Points: {CurrentTotalGameScore}"Funkcja zwracająca wynik
messageo nazwiePendingScoreText, która tworzy możliwy do zlokalizowania tekst, który może być wyświetlany w UI dla liczby punktów, jakie gracz ma obecnie zgromadzone za dany zbiór odebranych przedmiotów.PendingScoreText<localizes>(CurrentPendingScore : int) : message = "Pending Points: {CurrentPendingScore}"Funkcja zwracająca wynik
messageo nazwiePickupLevelText, która tworzy możliwy do zlokalizowania tekst, który może być wyświetlany w UI dla bieżącego poziomu odbioru.PickupLevelText<localizes>(CurrentPickupLevel : int) : message = "Pickup Level: {CurrentPickupLevel}"Dodaj wyrażenie
block, które tworzy widżet kanwy i umieszcza tekst rozmieszczony pionowo z lewej strony ekranu.<# W czasie życia menedżera wyników nie będziemy ponownie tworzyć kanwy, dlatego należy utworzyć ją raz przy każdym tworzeniu obiektu tego typu. #> block: set Canvas = canvas: Slots := array: canvas_slot: Anchors := anchors{Minimum := vector2{X := 0.0, Y := 0.25}, Maximum := vector2{X := 0.0, Y := 0.25} } Offsets := margin{Top := 0.0, Left := 25.0, Right := 0.0, Bottom := 0.0} Alignment := vector2{X := 0.0, Y := 0.0} SizeToContent := true Widget := stack_box: Orientation := orientation.Vertical Slots := array: stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := TotalGameScoreWidget stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := PendingScoreWidget stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := PickupLevelWidget
Otrzymany kod wyników
score_managerpowinien wyglądać następująco:using { /UnrealEngine.com/Temporary/UI } using { /Fortnite.com/UI } using { /Verse.org/Colors } score_manager := class: var Canvas<internal> : canvas = canvas{} TotalGameScoreWidget<internal> : text_block = text_block{DefaultTextColor := NamedColors.White} PendingScoreWidget<internal> : text_block = text_block{DefaultTextColor := NamedColors.White} PickupLevelWidget<internal> : text_block = text_block{DefaultTextColor := NamedColors.White} MaybePlayer<internal> : ?agent = false MaybePlayerUI<internal> : ?player_ui = false ScoreManagerDevice<internal> : score_manager_device = score_manager_device{} PickupLevelText<private><localizes>(InLevel : int) : message = "Poziom odbioru: {InLevel}" PendingScoreText<private><localizes>(InPoints : int) : message = "Punkty oczekujące: {InPoints}" TotalGameScoreText<private><localizes>(InPoints : int) : message = "Łączna liczba punktów: {InPoints}" var TotalGameScore<private> : int = 0 var PendingScore<private> : int = 0 var PickupLevel<private> : int = 0 <# W czasie życia menedżera wyników nie będziemy ponownie tworzyć kanwy, dlatego należy utworzyć ją raz przy każdym tworzeniu obiektu tego typu. #> block: set Canvas = canvas: Slots := array: canvas_slot: Anchors := anchors{Minimum := vector2{X := 0.0, Y := 0.25}, Maximum := vector2{X := 0.0, Y := 0.25} } Offsets := margin{Top := 0.0, Left := 25.0, Right := 0.0, Bottom := 0.0} Alignment := vector2{X := 0.0, Y := 0.0} SizeToContent := true Widget := stack_box: Orientation := orientation.Vertical Slots := array: stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := TotalGameScoreWidget stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := PendingScoreWidget stack_box_slot: HorizontalAlignment := horizontal_alignment.Left Widget := PickupLevelWidgetUtwórz funkcję o nazwie
UpdateUI()zawierającą specyfikatorprivate, która będzie aktualizować tekst w UI o najnowsze wartości wyniku i bieżący poziom odbioru.UpdateUI<private>() : void = if (PlayerUI := MaybePlayerUI?): PickupLevelWidget.SetText(PickupLevelText(PickupLevel)) PendingScoreWidget.SetText(PendingScoreText(PendingScore)) PendingScoreWidget.SetText(TotalGameScoreText(TotalGameScore))Utwórz funkcję o nazwie
AddScoreManagerToUI(), która będzie aktualizować UI gracza o niestandardowy UI menedżera wyników.AddScoreManagerToUI<public>() : void = if (PlayerUI := MaybePlayerUI?): PlayerUI.AddWidget(Canvas) UpdateUI()Utwórz następujące funkcje dla każdej wartości wyświetlanej w UI, aby pętla gry mogła aktualizować wartości:
Funkcja o nazwie
AddPendingScoreToTotalScore()zawierająca specyfikatorpublic. Funkcja powinna dodawać wynik oczekujący do łącznego wyniku gry, a następnie resetować wartość wyniku oczekującego do0. Za pomocą wyrażeniadefermożna opóźnić resetowanie wynikuPendingScorei zaktualizować UI po aktualizacji wynikuTotalGameScore. Pozwala to uniknąć przytrzymywania wartości wynikuPendingScoreprzez zmienną tymczasową przed jego zresetowaniem.Verse<# Adds PendingScore to TotalGameScore and resets PendingScore to 0.#> AddPendingScoreToTotalScore<public>() : void = defer: set PendingScore = 0 UpdateUI() set TotalGameScore += PendingScoreFunkcja o nazwie
UpdatePendingScore()zawierająca specyfikatorpublici parametr liczby całkowitej o nazwiePoints, który funkcja doda do aktualnego oczekującego wyniku.Verse<# Adds the given amount of points to the pending points. #> UpdatePendingScore<public>(Points : int) : void = set PendingScore += Points UpdateUI()Funkcja o nazwie
UpdatePickupLevelzawierająca specyfikatorpublicoraz parametr liczby całkowitej o nazwieLeveloznaczający nową wartość bieżącego poziomu odbioru.VerseUpdatePickupLevel<public>(Level : int) : void = set PickupLevel = Level UpdateUI()Utwórz funkcję o nazwie
AwardScore()zawierającą specyfikatorpublic. Funkcja ta przyznaje graczowi wynik za pomocą urządzenia menedżera wyniku oraz aktywuje to urządzenie.Verse<# Awards the score to the player with the Score Manager device, by activating it. #> AwardScore<public>() : void = ScoreManagerDevice.SetScoreAward(TotalGameScore) if (AwardedPlayer := MaybePlayer?): ScoreManagerDevice.Activate(AwardedPlayer)
Klasa
score_managerpowinna teraz wyglądać następująco:Versescore_manager := class: <# Since we won't recreate the canvas during the score manager lifetime, do it once anytime an object of this type is created.> block: set Canvas = canvas: Slots := array: canvas_slot: Anchors := anchors{Minimum := vector2{X := 0.0, Y := 0.25}, Maximum := vector2{X := 0.0, Y := 0.25} } Offsets := margin{Top := 0.0, Left := 25.0, Right := 0.0, Bottom := 0.0} Alignment := vector2{X := 0.0, Y := 0.0} SizeToContent := trueMasz już utworzoną klasę
score_manager. Teraz utwórz konstruktor dla klasy, aby inicjować zmienne gracza z poziomu gry. Pamiętaj, że w celu uzyskania odwołania do UI gracza musisz przeprowadzić rzutowanie typu odwołania do gracza zagentnaplayer.VerseMakeScoreManager<constructor><public>(InPlayer : agent, InScoreManagerDevice : score_manager_device) := score_manager: MaybePlayer := option{InPlayer} MaybePlayerUI := option{GetPlayerUI[player[InPlayer]]}Otrzymany plik score_manager.verse powinien wyglądać następująco:
Verseusing { /UnrealEngine.com/Temporary/SpatialMath} using { /UnrealEngine.com/Temporary/UI } using { /Fortnite.com/Devices } using { /Fortnite.com/UI } using { /Verse.org/Colors } using { /Verse.org/Simulation } MakeScoreManager<constructor><public>(InPlayer : agent, InScoreManagerDevice : score_manager_device) := score_manager: MaybePlayer := option{InPlayer} MaybePlayerUI := option{GetPlayerUI[player[InPlayer]]}
Aktualizacja wyniku i UI w pętli gry
Aby utworzyć, a następnie aktualizować UI w trakcie gry w pliku game_coordinator_device.verse, wykonaj następujące instrukcje:
Dodaj następujące właściwości do klasy
game_coordinator_device:Zmienna
score_managero nazwieScoreManagerzawierająca specyfikatorprivate. Ta instancja zarządza wynikiem gracza i UI.var ScoreManager<private> : score_manager = score_manager{}Edytowalna wartość
score_manager_device, dla której można ustawić urządzenie menedżera wyniku w konkretnym poziomie. Jest to urządzenie, którego będzie używać klasascore_manager.@editable ScoreManagerDevice<public> : score_manager_device = score_manager_device{}Edytowalna tablica liczb całkowitych o nazwie
PointsForPickupLevelzawierająca specyfikatorpublic, która służy do definiowania punktów, jakie gracz może zdobyć za każdy poziom odbioru.@editable # Mapuje liczbę punktów, jaka przysługuje za odbiór, w zależności od poziomu odbioru. PointsForPickupLevel<public> : []int = array{1, 2, 3}
W funkcji
StartGamezainicjuj zmienną menedżera wyników, wywołując konstruktorMakeScoreManager()z odwołaniem do gracza i urządzeniem menedżera wyniku, a następnie wygeneruj UI widoczne dla gracza.VerseStartGame<private>()<suspends> : void = Logger.Print("Trying to start the game...") # We construct a new countdown_timer that'll countdown from InitialCountdownTime once started. # Also construct a new score_manager that'll keep track of the player's score and pickup level. # The countdown_timer and score_manager require a player to show their UI to. # We should have a valid player by now: the one that entered the vehicle, triggering the game start. if (ValidPlayer := MaybePlayer?): Logger.Print("Valid player, starting game...")W funkcji
PickupDeliveryLoop()pętli gry aktualizuj UI po każdej zmianie poziomu odbioru i zakończeniu przez gracza odbioru lub dostarczenia:VersePickupDeliveryLoop<private>()<suspends> : void = PickupZonesTags : []pickup_zone_tag = array{pickup_zone_level_1_tag{}, pickup_zone_level_2_tag{}, pickup_zone_level_3_tag{}} MaxPickupLevel := PickupZonesTags.Length - 1 FirstPickupZoneCompletedEvent := event(){} loop: var PickupLevel : int = 0 var IsFirstPickup : logic = true # Every time the loop restarts, we should reset the pickup level UI through the ScoreManager.Teraz, gdy odliczanie dobiegło końca, przyznaj graczowi wynik. W
HandleCountdownEnd()wywołajScoreManager.AwardScore().HandleCountdownEnd<private>(InPlayer : player)<suspends>:void= TotalTime := CountdownTimer.CountdownEndedEvent.Await() ScoreManager.AwardScore() EndGame.Activate(InPlayer)Otrzymany plik game_coordinator_device.verse powinien wyglądać następująco:
Verseusing { /Verse.org/Simulation } using { /Fortnite.com/Devices } using { /Fortnite.com/Vehicles } using { /Fortnite.com/Characters } using { /Fortnite.com/Playspaces } using { /Verse.org/Random } using { /UnrealEngine.com/Temporary/Diagnostics } using { /UnrealEngine.com/Temporary/SpatialMath } using { /EpicGames.com/Temporary/Curves } using { /Verse.org/Simulation/Tags }