Postać w tym przykładzie wykorzystuje definicję postaci typu Niestandardowa, ponieważ postać ta musi jedynie się poruszać i nie potrzebuje dostępu do interfejsu API strażnika ani zwierzęcia. Za sterowanie zachowaniem postaci odpowiada niestandardowe zachowanie Verse o nazwie verse_commander_character.
Strażnicy są postaciami niezależnymi (NPC), które mogą poruszać się wzdłuż wyznaczonej ścieżki i przybierać wrogie nastawienie skutkujące zaatakowaniem wrogich graczy. Dzikie zwierzęta to zwierzęta, takie jak kurczak i dzik, które mogą poruszać się po wyznaczonych ścieżkach i atakować wrogich graczy.
Aby przystąpić do tworzenia niestandardowego NPC, utwórz nowe zachowanie NPC o nazwie vese_commander_character przy użyciu Eksploratora Verse. Informacje na temat tworzenia własnych zachowań niestandardowych postaci niezależnych zawiera temat Create Custom NPC Behavior (Tworzenie niestandardowych zachowań postaci niezależnych).
Postać musi znać następujące właściwości i nimi zarządzać:
CommandWaitTime: Określa czas oczekiwania między poszczególnymi poleceniami.
FocusTime: Określa czas skupienia na celu. Obracaniem się postaci w lewo lub w prawo steruje
focus_interfacepostaci, który wymusza skierowanie postaci przodem do konkretnego punktu z jej prawej lub lewej strony. Skupianie na celu zostaje zakończone dopiero w momencie przerwania, więc właściwość ta ma bardzo niską wartość, wystarczającą jedynie do tego, aby postać zwróciła się przodem w pożądanym kierunku.ReachRadius: Określa, jak blisko swojego celu nawigacji musi znaleźć się postać, aby program uznał, że “dotarła” do celu.
VerseCommanderMinigame: Jest to odwołanie do VerseCommanderMinigame w poziomie i umożliwia postaci nasłuchiwanie poleceń z tego elementu.
Odwołania do VFX i strzałek: Są to odwołania do różnych efektów VFX teleportowania do danego miejsca i z danego miejsca, a także do rekwizytu strzałki skierowanej naprzód, która ułatwia odczytanie orientacji postaci.
Verse# A Verse-authored NPC Behavior that can be used within an NPC Definition or a Character Spawner device's Behavior Script Override. verse_commander_character<public> := class(npc_behavior): # The VFX that play when the NPC teleports out. @editable CharacterTeleportOutVFX:vfx_spawner_device = vfx_spawner_device{} # The VFX that play when the NPC teleports in. @editable CharacterTeleportInVFX:vfx_spawner_device = vfx_spawner_device{}Po zdefiniowaniu właściwości postaci czas przejść do zdefiniowania ich zachowań oraz funkcji, które będą nimi sterować.
Ruch postaci
Postać w tej grze podejmuje następujące zachowania:
Ruch do przodu: Polecenie Do przodu powoduje przemieszczenie postaci o 1 kafelek na planszy do przodu.
Skręt w prawo lub Skręt w lewo: Polecenia Skręt w prawo i Skręt w lewo pozwalają wykonać zwrot postaci o 90 stopni, aby była skierowana przodem odpowiednio w prawo lub w lewo. W przypadku tej czynności postać nie wychodzi poza pole, na którym się znajduje.
Reset: Po wydaniu polecenia Reset postać teleportuje się z powrotem do pozycji początkowej na planszy.
Oczekiwanie na polecenia: Ruchem postaci nie da się sterować bezpośrednio, dlatego postać musi nasłuchiwać poleceń napływających z urządzenia VerseCommanderMinigame w poziomie. Po wykonaniu wszystkich wydanych poleceń postać będzie stać nieruchomo w oczekiwaniu na kolejne polecenia.
NPC w tym szablonie ma tylko kilka opcji ruchu: może poruszać się do przodu o jeden kafelek w kierunku, w którym jest zwrócona przodem, wykonać skręt w prawo lub wykonać skręt w lewo. Każdą z tych opcji realizuje się za pomocą funkcji GetNavTarget(), która tworzy nowy cel nawigacji oddalony od postaci o jedną odległość TileDistance. W zależności od tego, czy wydawane jest polecenie ruchu w przód, w prawo czy w lewo, celem jest lokalna pozycja z przodu, z prawej lub z lewej postaci.
# Gets a new navigation target for the NPC based on the current transform and the given command.
GetNavTarget(CurrentTransform:transform, Command:command, TileDistance:vector3):transform=
# Based on the command, get the character's local forward, right, or left (negative right).
Direction :=
if (Command = Commands.Forward):
CurrentTransform.Rotation.GetLocalForward()
else if (Command = Commands.TurnRight):
CurrentTransform.Rotation.GetLocalRight()
else if (Command = Commands.TurnLeft):
-CurrentTransform.Rotation.GetLocalRight()
Gdy NPC otrzyma sygnał wykonania, rozpoczyna powtarzanie listy poleceń i przekazuje każde z nich do funkcji ExecuteCommand(). Najpierw pobiera focus_interface i interfejs navigatable dla postaci, a następnie wykonuje różne czynności, w zależności od polecenia. Dla każdego polecenia ruchu do przodu albo skrętu w prawo lub w lewo wywoływana jest funkcja GetNavTarget(), która pozwala odszukać nowe przekształcenie, którego użyje NPC. Następnie postać kieruje się do przodu ku nowemu przekształceniu, wykorzystując NavigateTo() z interfejsu navigatable, lub skupia się na celu z jej prawej lub lewej strony, wykorzystując focus_interface.
# Executes the given command, either moving the NPC forward one tile or turning them left
# or right.
ExecuteCommand(Command:command, TileSize:vector3)<suspends>:void=
if:
# Get the Agent (the NPC).
Agent := GetAgent[]
# Gets the Fortnite Character interface, which gets you access to its gameplay data
# including its AI module for navigation and focus.
Character := Agent.GetFortCharacter[]
VFX postaci
Gdy postać porusza się po planszy, rekwizyt strzałki wskazuje pozycję oraz orientację postaci, aby ułatwić wizualizowanie postaci za pomocą kamery odgórnej. Strzałka ta musi podążać za postacią na planszy i aktualizować się zgodnie ze skrętami lub ruchami postaci. Funkcja MoveArrow() aktualizuje pozycję strzałki zgodnie z ruchem postaci, kopiując jej pozycję oraz orientację. Funkcja CreateArrow() generuje rekwizyt strzałki i wykonuje wywołanie początkowe do MoveArrow(), aby użytkownik od początku widział, gdzie znajduje się postać.
# Creates an arrow prop at the NPC's position that visually shows the orientation of the NPC.
CreateArrow(Agent:agent):void=
if :
Character := Agent.GetFortCharacter[]
then:
var Transform:transform = Character.GetTransform()
# Spawn the arrow prop, then set the mesh and material for the prop.
SpawnPropResult := SpawnProp(ForwardArrowAsset, Transform)
if:
SpawnedProp := SpawnPropResult(0)?
Gdy postać zostanie zespawnowana na planszy, przeniesiona na nową planszę lub zresetowana do pozycji początkowej na planszy za pomocą polecenia Reset, animacja teleportacji odtworzy zarówno animację teleportacji do miejsca, jak i teleportacji z miejsca. Aby utworzyć efekt teleportacji, najpierw wywołamy Hide() dla postaci oraz strzałki, a następnie odtworzymy TeleportOutVFX, przenosząc spawner VFX w miejsce, gdzie znajduje się postać, i uruchamiając go w tym miejscu. Po zakończeniu emitowania VFX teleportacji z miejsca, trzeba teleportować postać do nowej pozycji i odtworzyć w tym miejscu efekt TeleportInVFX. Po wykonaniu tych wszystkich czynności możemy wywołać Show() dla postaci oraz rekwizytu strzałki, aby wskazywał postać w jej nowej pozycji.
# Hides the NPC and the arrow prop, then teleports both to a new position,
# playing VFX for teleporting in and teleporting out.
PlayVFXAndMoveCharacter(StartPosition:transform)<suspends>:void=
if:
Agent := GetAgent[]
FortCharacter := Agent.GetFortCharacter[]
then:
# Hide the NPC and the arrow.
FortCharacter.Hide()
ForwardArrow.Hide()
Teleportowanie postaci odbywa się za pomocą funkcji pomocnika MoveToTile(), która pobiera przekształcenie w celu przeniesienia postaci do danego miejsca i teleportuje je w to miejsce. Do wartości Z przekształcenia dodane jest niewielkie przesunięcie, aby postać nie przenikała podłogi.
# Teleports the NPC to the given transform.
MoveToTile(Transform:transform)<transacts><decides>:void=
# Get the Agent (the NPC).
Agent := GetAgent[]
# Gets the Fortnite Character interface, which gets you access to its gameplay data
# including its AI module for navigation and focus.
Character := Agent.GetFortCharacter[]
var NewTransform:transform = Transform
Przetwarzanie poleceń
Gdy postać bezczynnie stoi na planszy, musi usiąść i nasłuchiwać sygnału wykonywania, aby wiedzieć, co robić dalej. Za realizację tego procesu odpowiada funkcja AwaitCommands(). Funkcja ta ma specyfikator suspends, dzięki czemu można ją wykonywać asynchronicznie, ponieważ postać musi wykonywać Await() w oczekiwaniu na zdarzenie ExecuteCommandsEvent. Polecenia napływają w formie krotki zawierającej tablicę poleceń oraz właściwość TileSize używaną w tych poleceniach, dlatego każde z nich musi być przetwarzane w pętli for poprzez wywołanie ExecuteCommand(). W miarę wykonywania poszczególnych poleceń ukrywamy strzałkę skierowaną w przód i pokazujemy ją dopiero po zakończeniu wykonywania polecenia. Gdy wszystkie polecenia zostaną wykonane sygnalizujemy minigrze Verse Dowódca, że to koniec wykonywania poleceń i można wydawać nowe.
# Waits for commands to be sent from the verse_commander_minigame, then
# executes each command.
AwaitCommands()<suspends>:void=
if:
Agent := GetAgent[]
then:
# Wait for commands to be sent from the verse commander minigame.
ExecuteResult := VerseCommanderMinigame.ExecuteCommandsEvent.Await()
# For each execute result tuple, execute the command and pass the tile size from the tuple.
Zamiast przetwarzania nowych poleceń, można również przywrócić postać do pozycji początkowej na bieżącej planszy za pomocą przycisku Reset. Resetowanie odbywa się natychmiast i nie wykorzystuje kolejki poleceń, więc postać musi nasłuchiwać tego polecenia niezależnie od sygnału wykonywania. Wykorzystuje się w tym celu funkcję AwaitReset(), która oczekuje na zasygnalizowanie zdarzenia BoardResetEvent z minigry Verse Commander. Gdy taki sygnał napłynie, funkcja wywołuje PlayVFXAndMoveCharacter(), aby przenieść postać z powrotem do pozycji początkowej na planszy.
# Waits for the current board to be reset, then moves the
# NPC back to the starting position of the board along with VFX.
AwaitReset()<suspends>:void=
# Wait for the current board to be reset.
# The event payload is the starting position for the board.
StartPosition := VerseCommanderMinigame.BoardResetEvent.Await()
spawn{PlayVFXAndMoveCharacter(StartPosition)}Uruchamianie pętli gry postaci
Po skonfigurowaniu różnych funkcji przetwarzających polecenia czas utworzyć główną pętlę gry postaci. Postać musi nieustannie nasłuchiwać sygnału wykonywania wyzwalającego przetwarzanie listy poleceń lub sygnału resetowania, który wyzwoli jej przeniesienie do punktu początkowego planszy. Oczekiwanie na sygnał wykonywania oraz sygnał resetowania musi się odbywać asynchronicznie i dla każdej planszy może występować wielokrotnie, więc konieczne jest rozdzielenie funkcji pomocnika obsługującej wykonywanie pętli każdego z tych procesów. Służy do tego funkcja CharacterCommandLoop(), która wykonuje główną pętlę gry dla postaci. W wyrażeniu race AwaitReset() wykonuje ona operację race między funkcją a pętlą, która stale wywołuje AwaitCommands(), aby mieć pewność, że postać zawsze nasłuchuje poleceń.
# Race between resetting the character to start of the board and awaiting commands for that character.
CharacterCommandLoop()<suspends>:void=
race:
AwaitReset()
loop:
AwaitCommands()Po rozpoczęciu gry postać pojawi się w poziomie dopiero po zespawnowaniu jej przy użyciu generatora NPC. Oznacza to, że po zespawnowaniu, postać musi znaleźć w poziomie minigrę Komandor Verse, ponieważ nie ma do niej odwołania. W tym celu wykorzystuje GetCreativeObjectsWithTag() do wyszukania tagu rozgrywki verse_commander_minigame_tag, ustawiając go jako VerseCommanderMinigame. Tworząc własną przygodę w formie minigry, pamiętaj o właściwym ustawieniu tagów, aby postacie w poziomie mogły odnaleźć obiekty, z którymi muszą się komunikować.
Po odnalezieniu minigry Komandor Verse postać musi zespawnować strzałkę wskazującą przód, która będzie za nią podążać. W tym celu wykorzystuje CreateArrow(). Aby wykonać pętlę gry, trzeba nieustannie wykonywać w pętli funkcję CharacterCommandLoop(), aby uruchomić pętlę ponownie w razie wystąpienia sygnału resetowania. Tak samo należy postąpić w wyrażeniu race w odniesieniu do zdarzenia GameEndedEvent z minigry Komandor Verse, ponieważ w przypadku zakończenia gry postać powinna niezwłocznie zaprzestać wykonywania bieżących czynności.
# This function runs when the NPC is spawned in the world and ready to follow a behavior.
OnBegin<override>()<suspends>:void=
# Get the Verse Commander Minigame Device.
# Assumption is that there is only one device in the level.
CreativeObjects := GetCreativeObjectsWithTag(verse_commander_minigame_tag{})
if:
CreativeObject := CreativeObjects[0]
MinigameManager := verse_commander_minigame[CreativeObject]
then:
Następny krok
Zdefiniowaliśmy niestandardową postać niezależną, która pobiera dane poleceń z urządzenia Verse i wykorzystuje je do poruszania się po planszy. Kompletny kod pozwalający utworzyć postać niestandardową znajdziesz w ostatnim kroku 7. Efekt końcowy.
W kolejnym kroku dowiesz się, jak utworzyć planszę, po której postać będzie mogła się poruszać i rozwiązać zamieszczoną na niej łamigłówkę.