Narzędzie Scene Graph udostępnia wiele sposobów tworzenia elastycznej i dynamicznej rozgrywki dzięki wielu różnym interakcjom między jednostkami i komponentami. W tym szablonie zaprezentowano kilka sposobów manipulowania jednostkami w czasie wykonywania, które polegają na spawnowaniu i usuwaniu jednostek, a także pokazano, jak można wykorzystać zdarzenia i zapytania komponentów do komunikacji między jednostkami i budowania elementów rozgrywki wielokrotnego użytku.
Spawnowanie i usuwanie gotowców
Na przykład przyjrzyj się płytce interaktywnej w drugim korytarzu. Gdy gracz staje na płytce, do sceny jest dodawany gotowiec latarni, który zostanie usunięty po zejściu przez gracza z płytki.
Otwórz plik SpawnPrefabDevice.verse i sprawdź, jak działa ten kod. Jest to urządzenie trybu kreatywnego, które wykorzystuje urządzenie wolumenu, aby wykryć wejście gracza do niego. Następnie spawnuje gotowiec i usuwa go, gdy gracz zejdzie z wyzwalacza. W górnej części definicji klasy SpawnPrefabDevice edytowalny element TriggerVolume odwołuje się do wolumenu wyzwalacza na poziomie.
SpawnPrefabDevice := class(creative_device):
@editable
TriggerVolume:volume_device = volume_device{}Po rozpoczęciu gry urządzenie definiuje nowy gotowiec słupa oświetleniowego do spawnowania, a także pozycję, w którym ma go spawnować.
OnBegin<override>()<suspends>:void =
PrefabToSpawn:entity = LightPost.P_LightPost{}
SpawnTransform:transform = transform:
Translation := vector3:
Left := -9084.0
Up := -8.0
Forward := -919.0Następnie pobiera jednostkę symulacji i tworzy konteksty niepowodzenia, w których ma pracować. Najpierw używa wyrażenia loop, aby wielokrotnie wykonywać zawarty w nim kod, a po nim jest stosowane wyrażenie race między dwoma instrukcjami block.
if:
SimulationEntity := GetSimulationEntity[]
then:
loop:
race:
block:
TriggerVolume.AgentEntersEvent.Await()
SimulationEntity.AddEntities(array{ PrefabToSpawn })
PrefabToSpawn.SetGlobalTransform(SpawnTransform)
Pierwsza instrukcja block oczekuje, aż agent wejdzie do urządzenia wolumenu. Gdy tak się stanie, dodaje gotowiec latarni do sceny za pomocą funkcji AddEntities() i prawidłowo określa jego pozycję za pomocą funkcji SetGlobalTransform(). Druga instrukcja block oczekuje, aż agent opuści wolumen, i usuwa gotowiec z jednostki nadrzędnej (w tym przypadku z jednostki symulacji).
Te instrukcje block ścigają się w pętli i każda z nich jest zawsze wykonywana, więc gracz może wejść do wolumenu i wyjść z niego, aby respawnować słup oświetleniowy dowolną liczbę razy.
Kompletny skrypt
Poniżej znajduje się kompletny opis dodawania jednostki do sceny i usuwania jednostki ze sceny.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/SceneGraph }
using { /Verse.org/SpatialMath }
using { /UnrealEngine.com/Temporary/Diagnostics }
SpawnPrefabDevice := class(creative_device):
Nakładanie się jednostek
W drugim korytarzu także znajdują się przykłady, które prezentują różne sposoby interakcji jednostek. Na przykład jednostki z komponentem siatki mogą być ostrzegane w razie nakładania się z inną jednostką. Służą do tego zdarzenia EntityEnteredEvent i EntityExitedEvent komponentu siatki. Aby zobaczyć tę funkcjonalność w działaniu, zapoznaj się z przykładem UFO w drugim korytarzu.
Po rozpoczęciu gry krowa odtwarza animację, aby się unieść, tak jakby została porwana przez UFO. Krowa wykorzystuje zdarzenie EntityEnteredEvent komponentu siatki, aby wykryć sytuację, gdy nakłada się z UFO, a następnie ustawia się jako niewidoczna, aby wyglądać na ofiarę porwania.
Kod dla tego przykładu jest zdefiniowany w pliku EntityEnteredExampleComponent.verse. Otwórz ten plik w Eksploratorze Verse.
Klasa entity_entered_example_component zaczyna działanie od zdefiniowania edytowalnej tablicy Keyframes, na podstawie której ma zostać utworzona animacja porwania krowy. Ponadto definiuje zmienną StartTransform, która wskazuje początkową pozycję krowy w scenie.
entity_entered_example_component<public> := class<final_super>(component):
@editable
Keyframes:[]keyframed_movement_delta = array{}
var StartTransform:transform = transform{}W funkcji OnBeginSimulation() skrypt rozpoczyna działanie od pobrania komponentu fort_round_manager. Jest to interfejs do menedżera rund Fortnite, którego możesz używać w celu subskrybowania zdarzeń do rozpoczęcia i zakończenia rundy. W tym przykładzie skrypt subskrybuje funkcję OnRoundStarted() do rozpoczęcia rundy przy użyciu funkcji SubscribeRoundStarted(), co oznacza, że funkcja zostanie wykonana tylko na początku gry, a nie na początku symulacji.
OnBeginSimulation<override>():void =
(super:)OnBeginSimulation()
if:
FortRoundManager := Entity.GetFortRoundManager[]
then:
FortRoundManager.SubscribeRoundStarted(OnRoundStarted)Następnie w funkcji OnRoundStarted() skrypt zaczyna działanie od ustawienia zmiennej StartTransform na przekształcenie globalne jednostki. Później subskrybuje zdarzenie EntityEnteredEvent komponentu siatki do nowej funkcji OnEntityEntered(), która będzie aktywowana za każdym razem, gdy inna siatka będzie się nakładać z jednostką. Następnie spawnuje funkcję PlayCowAbductionAnimation(), aby rozpocząć podnoszenie krowy.
OnRoundStarted():void =
set StartTransform = Entity.GetGlobalTransform()
if:
Mesh := Entity.GetComponent[mesh_component]
then:
Mesh.EntityEnteredEvent.Subscribe(OnEntityEntered)
spawn { PlayCowAbdcutionAnimation() }Funkcja PlayCowAbductionAnimation() po prostu ustawia przekształcenie globalne krowy na jej przekształcenie początkowe i czeka przez krótki czas. Później pobiera komponenty ruchu siatki i klatki kluczowej z jednostki, włącza siatkę, aby krowa stała się widoczna, ustawia animację na komponent ruchu z klatką kluczową i odtwarza go.
PlayCowAbdcutionAnimation()<suspends>:void =
Entity.SetGlobalTransform(StartTransform)
Sleep(2.0)
if:
Mesh := Entity.GetComponent[mesh_component]
MovementComponent := Entity.GetComponent[keyframed_movement_component]
then:
set Mesh.Visible = true
MovementComponent.SetKeyframes(Keyframes, oneshot_keyframed_movement_playback_mode{})
MovementComponent.Play()Na koniec funkcja OnEntityEntered() jest używana do wykonywania kodu za każdym razem, gdy krowa nakłada się z inną jednostką (w tym przypadku z UFO). Gdy tak się stanie, ponownie pobiera komponenty siatki i ruchu z klatką kluczową, ale tym razem używa ich w celu zatrzymania odtwarzania trwających animacji oraz sprawienia, aby krowa stała się niewidoczna (co wywołuje wrażenie, że została porwana). Następnie spawnuje nową instancję funkcji PlayCowAbductionAnimation(), aby rozpocząć proces od nowa.
OnEntityEntered(OtherEntity:entity):void =
if:
Mesh := Entity.GetComponent[mesh_component]
MovementComponent := Entity.GetComponent[keyframed_movement_component]
then:
MovementComponent.Stop()
set Mesh.Visible = false
spawn { PlayCowAbdcutionAnimation() }Kompletny skrypt
Poniżej znajduje się kompletny skrypt na potrzeby porwania siatki Krowa z użyciem siatki UFO.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Verse.org/SceneGraph/KeyframedMovement }
using { /Verse.org/SpatialMath }
using { /Fortnite.com/Game }
entity_entered_example_component<public> := class<final_super>(component):
Wykonywanie zapytań o trafienia nakładania
Jednostki mogą też wykonywać zapytania dotyczące innych jednostek przy użyciu zapytań o nakładanie. Zamiast wykrywać wejście jednostki do określonej siatki lub wyjście jednostki z określonej siatki, można używać zapytań o nakładanie w celu zwracania każdej jednostki i komponentu nakładających się z określonym obszarem.
Obszarem tym może być sama jednostka, określona przestrzeń kolizji, taka jak kula lub sześcian, lub pozycja, z której ma być symulowana jednostka. Następnie jest zwracana lista elementów overlap_hit. Każdy element overlap_hit dostarcza informacje o komponencie lub wolumenie, na który nakłada się wolumen źródłowy. Możesz wykonać zapytanie o te komponenty, aby znaleźć powiązaną z nimi jednostkę.
Na przykład wejdź na interaktywną płytkę przed przykładem FindOverlapHits. Gdy wejdziesz w interakcję z płytką, UFO spawnuje niewidoczny wolumen kolizji i używa go do wykonania zapytania o nakładanie. Jeśli wolumen kolizji nakłada się z krową, UFO ją porywa.
Kod dla tego przykładu jest zdefiniowany w pliku FindOverlapHitsExampleComponent.verse. Otwórz ten plik w Eksploratorze Verse .
Klasa zaczyna działanie od zdefiniowania edytowalnego urządzenia wolumenu o nazwie Wyzwalacz odwołującego się do interaktywnej płytki, na którą wchodzi gracz, a także do zmiennej logic IsAbducting określającej, czy krowa jest porywana. Gdy komponent rozpoczyna symulację, subskrybuje funkcję OnRoundStarted() do rozpoczęcia rundy menedżera rund. Podobnie funkcja OnRoundStarted() po prostu subskrybuje zdarzenia AgentEntersEvent i AgentExitsEvent z urządzenia Wyzwalacz odpowiednio do funkcji OnTriggerEntered() i OnTriggerExited().
find_overlaphits_example_component<public> := class<final_super>(component):
@editable
Trigger:volume_device = volume_device{}
var IsAbducting:logic = false
OnBeginSimulation<override>():void =
Gdy gracz stanie na płytce, a UFO obecnie nie porywa krowy, jest wywoływana funkcja OnTriggerEntered() w celu wstrzymania ruchu wykonywanego przez UFO poprzez pobranie jego komponentu keyframed_movement_component i wywołanie funkcji Pause(). Następnie wywołuje funkcje EnableAbductionBeam() i PerformOverlapCheck(), aby włączyć promień porywający i sprawdzić, czy krowa znajduje się pod UFO.
OnTriggerEntered(Agent:agent):void=
if:
not IsAbducting?
MovementComponent := Entity.GetComponent[keyframed_movement_component]
then:
MovementComponent.Pause()
EnableAbductionBeam()
PerformOverlapCheck()Rzeczywista logika sprawdzania nakładania jest przechowywana w funkcji PerformOverlapCheck(). Aby symulować promień porywający, ta funkcja spawnuje kapsułę kolizji i definiuje przekształcenie CollisionTransform, które jest ustawione na miejsce znajdujące się bezpośrednio pod UFO.
PerformOverlapCheck():void =
CollisionCapsule := collision_capsule{Radius := 36.0, Length := 328.0}
var CollisionTransform:transform = Entity.GetGlobalTransform()
set CollisionTransform.Translation.Up = CollisionTransform.Translation.Up - 248.0Następnie w wyrażeniu for funkcja wywołuje funkcję FindOverlapHits() w celu znalezienia i zwrócenia komponentów lub wolumenów. Przekazuje CollisionCapsule jako wolumen, w którym ma zostać sprawdzona kolizja, a CollisionTransform jako miejsce, z którego ma zostać zasymulowana ta kolizja. Później wykonuje iterację przy każdym nakładaniu i sprawdza, czy nakładający się komponent był komponentem siatki (w szczególności siatką SM_Toy_Cow z jednostki krowy). Jeśli tak było, spawnuje funkcję AbductCow() przekazującą krowę do porwania.
# Perform the overlap check from the entity that contains the mesh_component
for:
Overlap : Entity.FindOverlapHits(CollisionTransform, CollisionCapsule)
# Cast to see if what was overlapped was the Cow
CowMesh := Meshes.SM_Toy_Cow[Overlap.TargetComponent]
CowPrefab := CowMesh.Entity
do:
spawn { AbductCow(CowPrefab) }Aby symulować porwanie krowy, jednostka buduje animację, a następnie odtwarza ją na jednostce krowy, podobnie jak w powyższym przykładzie Nakładanie się jednostek. Ten kod jest wywoływany z jednostki UFO, a nie z krowy, więc musi pobrać komponenty z jednostki krowy, a następnie przekazać animację do odtworzenia. Rozpoczyna działanie od pobrania komponentów siatki i ruchu z klatką kluczową od krowy, a następnie ustawia zmienną IsAbducting na wartość true.
AbductCow(CowEntity:entity)<suspends>:void =
# Get the components on the Cow Prefab
if:
CowMesh := CowEntity.GetComponent[mesh_component]
MovementComponent := CowEntity.GetComponent[keyframed_movement_component]
then:
set IsAbducting = trueKlatka kluczowa używana w animacji porwania krowy nie jest ustawiana w panelu Outliner, więc kod musi ją zbudować na podstawie różnicy pozycji UFO i krowy. W tym celu pobiera różnicę w translacji krowy i UFO, a następnie na podstawie tych wartości tworzy nowy element keyframed_movement_delta. Później ustawia tę pojedynczą klatkę kluczową jako tablicę w komponencie ruchu z klatką kluczową i wywołuje odtwarzanie, aby umożliwić animowanie krowy między jej pozycją początkową a UFO.
# Get the delta between Cow and UFO
DeltaTransform:transform = transform:
Translation:= Entity.GetGlobalTransform().Translation - CowEntity.GetGlobalTransform().Translation
Scale := vector3{Left:= 0.0, Up:= 0.0, Forward:= 0.0}
# Create a key frame
Keyframe := keyframed_movement_delta:
Transform := DeltaTransform
Duration := 2.0
Easing := ease_in_cubic_bezier_easing_function{}
W momencie porwania może wystąpić animacja z przemieszczeniem krowy do UFO, ale kod musi również spowodować zniknięcie krowy, gdy nałoży się ona z UFO. W tym celu kod oczekuje na zdarzenie EntityEnteredEvent komponentu siatki pochodzące od krowy, a następnie wywołuje funkcję RemoveFromParent() w celu usunięcia jednostki krowy ze sceny. Krowa zniknęła, więc UFO może ponownie rozpocząć patrolowanie. Z tego powodu kod wywołuje odtwarzanie komponentu ruchu z klatką kluczową UFO, aby znowu się ono przemieszczało.
# Wait for Entity Entered Event
CowMesh.EntityEnteredEvent.Await()
# Remove Cow from world
CowEntity.RemoveFromParent()
# Resume UFO Patrol
set IsAbducting = false
if:
UFOMovementComponent := Entity.GetComponent[keyframed_movement_component]
Na koniec funkcje EnableAdbuctionBeam() i DisableAbductionBeam() działają jak proste funkcje pomocnicze, które przy każdym wywołaniu odpowiednio włączają lub wyłączają komponenty siatki i światła reflektorowego promienia porywającego w UFO.
EnableAbductionBeam():void =
for:
Mesh : Entity.FindDescendantComponents(Meshes.S_EV_SimpleLightBeam_01)
do:
Mesh.Enable()
for:
Light : Entity.FindDescendantComponents(spot_light_component)
do:
Light.Enable()
Kompletny skrypt
Poniżej znajduje się kompletny skrypt do wykonywania zapytań o trafienia nakładania.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Verse.org/Colors }
using { /Verse.org/SceneGraph/KeyframedMovement }
using { /Verse.org/SpatialMath }
using { /Fortnite.com/Game }
using { /Fortnite.com/Devices }
Wykonywanie zapytań o trafienia omiatania
Trafienia omiatania to kolejny ważny sposób wykonywania zapytań o nakładanie się jednostek. Przesunięcie odnosi się do przesuwania obiektu na ustaloną odległość wzdłuż określonego wektora. Przykładem może być przemieszczenie bloku po platformie, aby zepchnąć graczy w szczelinę, lub wystrzelenie pocisku prosto do przodu, aby zniszczyć ścianę.
Funkcja FindSweepHits() zwraca listę elementów sweep_hit. Każdy element sweep_hit dostarcza te same informacje co element overlap_hit, takie jak informacje o trafieniu komponentu lub wolumenu oraz informacje o wolumenie źródłowym lub komponencie wykonującym omiatanie. Ponadto dostarcza informacje o pozycji kontaktu, normalnej, normalnej powierzchni i odległości wzdłuż omiatania, w przypadku którego nastąpiło trafienie.
Szablon wykorzystuje trafienia omiatania, aby zbudować bardziej zaawansowaną wersję poprzedniego przykładu trafień nakładania. Wejdź na ostatnią interaktywną płytkę w drugim korytarzu, aby sprawdzić ten przykład. Gdy staniesz na płytce, UFO spawnuje promień porywający. Następnie wykonuje trafienie omiatające od siatki UFO w dół, sprawdzając pierwszą jednostkę, z którą nakłada się omiatanie. Jeśli jednostką jest krowa, UFO porywa ją tak jak zwykle. Jeśli jednak krowa jest chroniona przez jednostkę kuli, omiatanie najpierw trafi w kulę i zostanie zablokowane, co uniemożliwi porwanie krowy przez UFO.
Otwórz plik FindOverlapHitsExampleComponent.verse w Eksploratorze Verse, aby zbadać kod. Tutaj konfiguracja jest bardzo podobna do konfiguracji z powyższego przykładu dotyczącego trafień nakładania. Jej logika jest taka sama jak ta, której używa się w przypadku porywania krowy oraz włączania i wyłączania promienia porywającego. Główna różnica polega na użyciu funkcji OnTriggerEntered(), która jest wykonywana, gdy gracz wejdzie na interaktywną płytkę przed przykładem.
Kod tej funkcji rozpoczyna się podobnie jak w przykładzie dotyczącym trafień nakładania: pobiera z jednostki komponent ruchu z klatką kluczową i włącza promień porywający.
OnTriggerEntered(Agent:agent):void=
# When a cow is inside the abduction area, stop the ship moving and start the abduction beam.
if:
not IsAbducting?
MovementComponent := Entity.GetComponent[keyframed_movement_component]
then:
MovementComponent.Pause()
EnableAbductionBeam()Jednak ta funkcja korzysta z omiatania zamiast nakładania, więc logika określająca, czy krowa znajduje się pod promieniem porywającym, jest nieco inna. Funkcja rozpoczyna działanie od pobrania pierwszego elementu podrzędnego jednostki UFO (w tym przypadku jest to jednostka siatki UFO). Następnie tworzy wektor przemieszczenia, od którego ma nastąpić omiatanie, skierowany prosto w dół od UFO.
# Perform the sweep from the UFO Mesh
if (Child := Entity.GetEntities()[0]):
DisplacementVector := vector3{Left:=0.0, Up:=-300.0, Forward:=0.0}Później używa tego wektora przemieszczenia w celu wywołania funkcji pomocniczej FindFirstSweepHit() oraz przekazuje siatkę UFO i wektor. Jeśli pierwszym komponentem jest komponent siatki krowy, spawnuje funkcję AbductCow() w celu symulowania porwania krowy.
# Perform the sweep from the UFO Mesh
if (Child := Entity.GetEntities()[0]):
DisplacementVector := vector3{Left:=0.0, Up:=-300.0, Forward:=0.0}
FirstSweepHitEntity := FindFirstSweepHit(Child, DisplacementVector)
# If the First Hit Entity is the Cow Mesh, then abduct the Cow
if (HitEntity := FirstSweepHitEntity?; HitEntity.GetComponent[Meshes.SM_Toy_Cow]):
spawn { AbductCow(HitEntity) }Funkcja FindFirstSweepHit() przyjmuje jednostkę do omiatania i wektor przemieszczenia, wzdłuż którego ma następować omiatanie. Wywołuje funkcję FindSweepHits() w celu symulowania omiatania, a następnie wykonuje iterację przy każdym zwracanym trafieniu omiatania w wyrażeniu „for”. Każdy element sweep_hit zawiera komponent lub wolumen, więc możesz wykonać zapytanie o komponent TargetComponent lub TargetVolume, aby poznać jego typ. W tym przypadku kod pobiera jednostkę będącą właścicielem komponentu TargetComponent i zwraca ją jako opcję, co oznacza, że zwróci wartość „true”, jeśli omiatanie trafi komponent. W przeciwnym razie zwróci wartość false.
# Returns the first Entity hit by FindSweepHits
FindFirstSweepHit(InEntity:entity, DisplacementVector:vector3):?entity =
for (SweepHit : InEntity.FindSweepHits(DisplacementVector)):
return option{ SweepHit.TargetComponent.Entity }
return falseKompletny skrypt
Poniżej znajduje się kompletny skrypt do wykonywania zapytań o trafienia omiatania.
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Verse.org/Colors }
using { /Verse.org/SceneGraph/KeyframedMovement }
using { /Verse.org/SpatialMath }
using { /Fortnite.com/Game }
using { /Fortnite.com/Devices }