Ta strona poprowadzi cię przez proces tworzenia nowego komponentu Scene Graph o nazwie trigger_component. Ten komponent aktywuje akcje na jednostkach zawierających komponent Scene Graph implementujący możliwy do aktywowania interfejs. Komponent trigger_component umożliwia agentom interakcję z systemem Scene Graph za pośrednictwem volume_device. Gdy agent wejdzie do volume_device lub go opuści, sygnalizowane jest odpowiednie zdarzenie AgentEnteredEvent i AgentExitedEvent oraz wywoływane są odpowiednie wywołania zwrotne w celu wykonania działań na komponentach i jednostkach Scene Graph.
Na poniższej ilustracji biały cokół na ziemi jest jednostką Scene Graph z trigger_component i niewidocznym volume_device wokół cokołu.
Gdy gracz stanie na cokole, trigger_component aktywuje dwa światła najbardziej wysunięte w prawo.
Gdy gracz zejdzie z cokołu i opuści volume_device, światła pozostają włączone.
Aby dowiedzieć się więcej na temat funkcji języka Verse używanych na tej stronie, patrz:
Definiowanie komponentu wyzwalacza
Przejdź do Eksploratora Verse, kliknij prawym przyciskiem myszy nazwę projektu i wybierz opcję Dodaj nowy plik Verse do projektu.
Wybierz szablon Komponent Scene Graph i zmień nazwę komponentu na trigger_component.
Zdefiniuj klasę
trigger_componenti dodaj pola, które odwołują się do powiązanegovolume_device, niezależnie od tego, czy ten komponent aktywuje tylko elementy podrzędne czy wszystkie możliwe do aktywowania elementy potomne, a także tablicę odwołującą się do wszystkich agentów wchodzących w interakcję z tym komponentem.Versetrigger_component := class<final_super>(component): # volume_device associated with this trigger_component @editable InteractionVolume<private>:volume_device = volume_device{} # whether or not this triggers on components on child entities @editable OnlyTriggerChildren:logic = falseDodaj funkcje o nazwach
OnAgentEntersVolumeiOnAgentExitsVolume, które określają, co się stanie, gdy agent wejdzie do urządzeniavolume_devicepowiązanego z tym komponentem i z niego wyjdzie. Gdy agent wejdzie do wolumenu, zarejestruj agenta wchodzącego w interakcję i poszukaj jednostek potomnych, które mają komponent implementującymożliwy do aktywowaniainterfejs, a następnie aktywuj komponent w tych jednostkach. Gdy agent wejdzie do wolumenu, usuń agenta wchodzącego w interakcję z listy agentów wchodzących w interakcję z tym wolumenem.Verse# Event that is triggered when an Agent enters the InteractionVolume OnAgentEntersVolume(Agent:agent):void= for: ChosenEntity : Entity.FindDescendantEntities(entity) ChosenEntityComponent : ChosenEntity.GetComponents() CastToInterface := triggerable[ChosenEntityComponent] do: if (OnlyTriggerChildren?): if (Entity = ChosenEntity.GetParent[]): CastToInterface.Trigger()Połącz funkcje
OnAgentEntersVolumeiOnAgentExitsVolumezvolume_device, rejestrując je jako funkcje wywołania zwrotnego dlaAgentEntersEventiAgentExitsEventw funkcjiOnSimulatetego komponentu.Verse# Runs when the component should start simulating in a running game. OnBeginSimulation<override>():void = # Run OnBeginSimulation from the parent class before # running this component's OnBeginSimulation logic (super:)OnBeginSimulation() # Runs when the component should start simulating in a running game. # Can be suspended throughout the lifetime of the component. Suspensions # will be automatically cancelled when the component is disposed or the # game ends.
Definiowanie komponentów możliwych do aktywowania
Następnie zdefiniuj komponenty, które implementują utworzony wcześniej interfejs możliwy do aktywowania. Są to komponenty dodawane do jednostek Scene Graph, które są elementami potomnymi jednostki z puzzle_component i są aktywowane przez jednostkę będącą przodkiem z trigger_component. W tym samouczku zdefiniowano trzy różne komponenty możliwe do aktywowania:
triggerable_mesh_component: Przełącza widoczność komponentumesh_componentjednostki.triggerable_light_component: Włącza i wyłącza komponentsphere_light_componentjednostki oraz zamienia komponentmesh_componentjednostki na taki z kolorem emisyjnym lub bez niego, w zależności od tego, czy światło jest włączone.triggerable_movement_component: Aktywuje przekształcenie komponentumesh_componentjednostki za pomocą komponentukeyframed_movement_component.
Te trzy różne komponenty mają wiele wspólnych funkcji, a wiele z nich definiuje się w ten sam sposób. Aby rozpocząć, utwórz nowy, pusty plik Verse o nazwie TriggerableComponents.verse.
Dołącz następujące moduły:
/Verse.org/SceneGraph, ponieważ ten plik wykorzystuje komponenty Scene Graph i zdarzenia sceny.
/Verse.org/SceneGraph/KeyframedMovement, ponieważ ten plik używa keyframed_movement_delta.
/Verse.org/Simulation, ponieważ ten plik używa atrybutu @editable.
/Verse.org/SpatialMath, ponieważ ten plik używa przekształceń Verse.
Verseusing { /Verse.org/SceneGraph } using { /Verse.org/SceneGraph/KeyframedMovement } using { /Verse.org/Simulation } using { /Verse.org/SpatialMath }Zdefiniuj komponenty
triggerable_mesh_component,triggerable_light_componentitriggerable_movement_component. Wszystkie te komponenty dziedziczą z bazowej klasykomponentui implementują interfejs możliwy do aktywowania.Wszystkie trzy komponenty implementują te same trzy zdarzenia:
OnReceive: Opcja wywoływana, gdy ten komponent odbierze zdarzenie sceny.OnBeginSimulation: Opcja wywoływana, gdy komponent powinien rozpocząć symulację.OnSimulate: Opcja wywoływana, gdy komponent rozpoczyna symulację.
Dodaj następujące implementacje do wszystkich trzech komponentów.
Verse# Runs when this component receives a scene event OnReceive<override>(SceneEvent:scene_event):logic= if (PuzzleSolvedEvent := puzzle_solved_event[SceneEvent], not PuzzlePiece?): Trigger() true false # Runs when the component should start simulating in a running game. OnBeginSimulation<override>():void = # Run OnBeginSimulation from the parent class beforeWszystkie trzy komponenty implementują również zastąpienie
możliwego do aktywacjiinterfejsuPostTriggerw ten sam sposób, wysyłająctriggered_eventw górę, jeśli komponentmożliwy do aktywowaniajest elementem łamigłówki. Nie można tego wykonać w samym interfejsiemożliwym do aktywowania, ponieważ Verse musi wiedzieć, którajednostkajest aktywowana, a poleJednostkajest częścią klasykomponentui jest niedostępne dla interfejsumożliwego do aktywowaniabez dodatkowej zależności od klasykomponentu.VersePostTrigger<override>():void = if (PuzzlePiece?): Event := triggered_event: Triggered := Triggered TriggeredEntity := option{Entity} Entity.SendUp(Event)
Aktywowany komponent siatki
Komponent triggerable_mesh_component przełącza widoczność mesh_component na jednostce. Wymaga to wprowadzenia zastąpień dla następujących funkcji możliwego do aktywowania interfejsu:
SetInitialTriggeredStatePerformActionPerformReverseAction
Początkowy stan aktywowania jest określany poprzez sprawdzenie, czy siatka na początku wyświetla się jako widoczna w świecie gry zgodnie z ustawieniami w panelu Szczegóły komponentu siatki.
Akcja
triggerable_mesh_componentpolega na wyświetleniu siatkimesh_component. W tym celu pobierzmesh_componentdla odpowiedniej jednostki, ustaw siatkę na widoczną, a następnie ustaw stantriggerable_mesh_componentna aktywowany.Verse# Determine the initial triggered state of this component SetInitialTriggeredState<override>():void= if (MeshComponent := Entity.GetComponent[mesh_component], MeshComponent.Visible?): set Triggered = trueAkcja odwrotna
triggerable_mesh_componentpolega na ustawieniu niewidoczności siatkimesh_component. W tym celu pobierzmesh_componentdla odpowiedniej jednostki, ustaw siatkę na niewidoczną, a następnie ustaw stantriggerable_mesh_componentna nieaktywowany.VersePerformReverseAction<override>():void = if (MeshComponent := Entity.GetComponent[mesh_component]): if (MeshComponent.Visible?): set MeshComponent.Visible = false set Triggered = false
Komponent ruchu z możliwością aktywowania
Komponent triggerable_movement_component aktywuje jednostkę, aby kolejno przemieściła się z jednej lokalizacji do serii innych lokalizacji za pomocą keyframed_movement_component. Wymaga to wprowadzenia zastąpień dla następujących funkcji możliwego do aktywowania interfejsu:
SetInitialTriggeredStatePerformActionPerformReverseAction
Ponadto komponent ten wykorzystuje kilka funkcji pomocniczych:
GetMovementStates: Pobiera przekształcenia jednostek podrzędnych definiujące serie przekształceń dla tej jednostki.MakeDeltaTransform: Tworzy przekształcenie delta między dwoma przekształceniami wejściowymi.ConstructKeyframeDeltas: Tworzy tablicę obiektówkeyframed_movement_deltana potrzeby danych wejściowych dokeyframed_movement_component.SetAndPlayAnimation: Przypisuje klatki kluczowe i odtwarza animację ruchu.
Dodaj do tej klasy edytowalną wartość zmiennopozycyjną, która określa czas trwania animacji z klatką kluczową.
Verse@editable Duration:float = 2.0Ta klasa implementuje interfejs
możliwy do aktywowania, dlatego dla funkcjiPerformActioniPerformReverseActionnależy wprowadzić zastąpienia, ponieważ nie mają one domyślnych implementacji. Ponieważ nie ma początkowego stanu aktywowania, a akcja jest ruchem między lokalizacjami, domyślnym początkowym stanem aktywowania jest false. To właśnie implementacja bazowa wykonuje w interfejsiez możliwością aktywowania, więc funkcja ta nie wymaga zastąpienia w tej klasie komponentu.Akcja
triggerable_movement_componentpolega na przemieszczeniu jednostki wzdłuż serii przekształceń zdefiniowanych przez jednostki podrzędne.VersePerformAction<override>():void = MovementStates := GetMovementStates() AnimationFrames:[]keyframed_movement_delta = ConstructKeyframeDeltas(MovementStates) SetAndPlayAnimation(AnimationFrames)Akcja odwrotna
triggerable_movement_componentpolega na przemieszczeniu jednostki wzdłuż serii przekształceń zdefiniowanych przez jednostki podrzędne w odwrotnej kolejności. Funkcja ta jest podobna doPerformAction, z tą różnicą, że tablica przekształcenia jest w odwrotnej kolejności.VersePerformReverseAction<override>():void = MovementStates := GetMovementStates() ReversedMovementStates := for: Index := 0..MovementStates.Length - 1 ReversedElement := MovementStates[MovementStates.Length - 1 - Index] do: ReversedElement AnimationFrames := ConstructKeyframeDeltas(ReversedMovementStates) SetAndPlayAnimation(AnimationFrames)Zdefiniuj funkcje pomocnicze używane przez ten komponent. Najpierw utwórz funkcję o nazwie
GetMovementStates,aby pobrać przekształcenia, do których przenosi się ten ruch.VerseGetMovementStates():[]transform= for (ChildEntity : Entity.FindDescendantEntities(entity), Entity = ChildEntity.GetParent[]): ChildEntity.GetGlobalTransform()Zdefiniuj funkcję pomocniczą o nazwie
MakeDeltaTransform, która konstruuje przekształcenie delta między dwoma przekształceniami. Przekształcenie delta, D, od przekształcenia A do przekształcenia B jest takim przekształceniem, że po zastosowaniu przekształcenia D do przekształcenia A wynikiem jest przekształcenie B.Aby rozwinąć tę kwestię, załóżmy, że masz jednostkę Scene Graph z bieżącym przekształceniem A, ale chcesz ją skalować, obracać i przesunąć, aby miała przekształcenie B. Przekształcenie delta D to przekształcenie potrzebne, aby zdarzenie
keyframed_movement_deltaanimowało ruch jednostki od przekształcenia A do przekształcenia B.VerseMakeDeltaTransform(InTransformOne:transform, InTransformTwo:transform):transform = transform: Translation := InTransformTwo.Translation - InTransformOne.Translation Rotation := MakeComponentWiseDeltaRotation(InTransformOne.Rotation, InTransformTwo.Rotation) Scale := vector3: Forward := InTransformTwo.Scale.Forward / InTransformOne.Scale.Forward Right := InTransformTwo.Scale.Right / InTransformOne.Scale.Right Up := InTransformTwo.Scale.Up / InTransformTwo.Scale.UpZdefiniuj funkcję pomocniczą o nazwie
ConstructKeyframeDelta, która tworzy tablicę obiektówkeyframed_movement_deltana potrzeby danych wejściowych w animacjikeyframed_movement_component.VerseConstructKeyframeDeltas<public>(MovementStates:[]transform):[]keyframed_movement_delta = var LastTransform:transform = Entity.GetGlobalTransform() for (EntityIndex -> CurrentTransform : MovementStates): DeltaTransform := MakeDeltaTransform(LastTransform, CurrentTransform) set LastTransform = CurrentTransform keyframed_movement_delta: Transform := DeltaTransform Duration := Duration Easing := if (MovementStates.Length > 1): if (EntityIndex = 0):Utwórz funkcję o nazwie
SetAndPlayAnimation, która przypisuje tablicękeyframed_movement_deltado animacjikeyframed_movement_componenti ją odtwarza.VerseSetAndPlayAnimation<private>(Frames:[]keyframed_movement_delta):void = if (KeyframedMovementComponent := Entity.GetComponent[keyframed_movement_component]): KeyframedMovementComponent.SetKeyframes(Frames, oneshot_keyframed_movement_playback_mode{}) KeyframedMovementComponent.Play()
Komponent światła z możliwością aktywowania
Komponent triggerable_light_component włącza i wyłącza światło. Wymaga to wprowadzenia zastąpień dla następujących funkcji możliwego do aktywowania interfejsu:
SetInitialTriggeredStatePerformActionPerformReverseAction
Początkowy stan aktywowania światła zależy od tego, czy światło jest włączone, dlatego
SetInitialTriggeredStatesprawdza, czy światło jest już włączone, a jeśli tak, ustawia je jako początkowo aktywowane.Verse# Determine the initial triggered state of this light SetInitialTriggeredState<override>():void= for: DescendantEntity : Entity.FindDescendantEntities(entity) Entity = DescendantEntity.GetParent[] MeshComponent := DescendantEntity.GetComponent[mesh_component] LightComponent := DescendantEntity.GetComponent[light_component] MeshComponent.IsEnabled[] LightComponent.IsEnabled[] do:Akcja wykonywana przez
triggerable_light_componentpolega na włączeniu światła i przełączeniu na siatkę wskazującą, że światło jest włączone.VersePerformAction<override>():void= if (not IsLightOn?): for (DescendantEntity:Entity.FindDescendantEntities(entity), Entity = DescendantEntity.GetParent[]): if (MeshComponent := DescendantEntity.GetComponent[mesh_component]): if (LightComponent := DescendantEntity.GetComponent[light_component]): MeshComponent.Enable() LightComponent.Enable() else: MeshComponent.Disable() set IsLightOn = trueAkcja wykonywana przez
triggerable_light_componentpolega na wyłączeniu światła i ustawieniu nieemisyjnego komponentumesh_componentna widoczny.VersePerformReverseAction<override>():void= if (IsLightOn?): for (DescendantEntity:Entity.FindDescendantEntities(entity), Entity = DescendantEntity.GetParent[]): if (MeshComponent := DescendantEntity.GetComponent[mesh_component]): if (LightComponent := DescendantEntity.GetComponent[light_component]): MeshComponent.Disable() LightComponent.Disable() else: MeshComponent.Enable() set IsLightOn = false
Kolejne kroki
Po napisaniu całego kodu Verse skompiluj go. Następnie zbuduj gotowce z bazowych jednostek i komponentów, które wykorzystasz w UEFN do stworzenia swojej łamigłówki.
Kod końcowy
TriggerComponent.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/SceneGraph }
using { Logging }
trigger_component<public> := class<final_super>(component):
@editable
InteractionVolume<private>:volume_device = volume_device{}
TriggerableComponents.verse
using { /Verse.org/SceneGraph }
using { /Verse.org/SceneGraph/KeyframedMovement }
using { /Verse.org/Simulation }
using { /Verse.org/SpatialMath }
EnabledToolTip<public><localizes>:message = "Whether or not this component is enabled."
triggerable_mesh_component<public> := class<final_super>(component, triggerable):
<# Triggerable interface #>