На этой странице описан порядок создания нового компонента Scene Graph с названием puzzle_component, который управляет головоломкой, созданной с помощью модулей Scene Graph. Созданный компонент puzzle_component поместите в модуль Scene Graph, чтобы определить, решена ли головоломка, состоящая из дочерних модулей Scene Graph с активируемыми компонентами, указанными в качестве деталей головоломки.
Например, на следующем изображении представлена простая головоломка, которую вы создадите в последнем разделе этого руководства.
На следующем рисунке показано окно «Структура», соответствующее этой головоломке.
Каждый дочерний модуль Prefab_PuzzleManager является частью головоломки, управляемой соответствующим компонентом Prefab_PuzzleManager — puzzle_component. Компонент puzzle_component:
Принимает события при переключении любой детали головоломки на решённую конфигурацию.
Определяет момент решения головоломки.
После успешного решения головоломки отправляет события вниз по иерархии Scene Graph для активации действий, соответствующих такому решению.
Когда игрок встаёт на платформы и включает оба источника света, сетка анимируется и преобразуется.
Дополнительная информация о функциях языка Verse, используемых на этой странице, приведена на следующих страницах:
Определение события состоявшегося решения головоломки
Для начала перейдите в проводник Verse, выберите правой кнопкой мыши название проекта и далее — Добавить новый файл Verse в проект.
Выберите шаблон Компонент Scene Graph и измените его название на puzzle_component.
Определите
puzzle_solved_event. Это событие, которое передаётся через иерархию Scene Graph в момент решения головоломки, чтобы активировать действие, к примеру, открытие ворот или выдвижение моста, чтобы игрок мог выйти за пределы области, огороженной головоломкой. Определитеpuzzle_solved_eventкак дочерний классscene_event. Это событие не требует передачи параметров вниз по иерархии.Versepuzzle_solved_event<public> := class(scene_event){}
Определение компонента головоломки
Далее определите puzzle_component с полями и функциями, которые будут управлять головоломкой и определять, решена она или нет.
Добавьте поля, которые позволят определить, решена ли головоломка, массив, из которого детали головоломки оказываются в решённой конфигурации, а также поля для определения того, будут ли детали головоломки активироваться после её решения:
Versepuzzle_component := class<final_super>(component): # Is this puzzle component solved var<private> Solved<public>:logic = false # Map of puzzle pieces and whether they have been "solved" var<private> TriggerableEntities<private>:[]entity = array{} # Disable puzzle pieces triggering once puzzle is solved @editableДобавьте функцию
InitializeTriggerableDescendantEntities, чтобы инициализировать список всех деталей головоломки, которые включены в эту головоломку. Эта функция проходит вниз по иерархии Scene Graph, чтобы найти все активируемые модули, помеченные как детали головоломки, и добавляет их в массивTriggerableEntities.Verse# Initialize array of triggerable entities InitializeTriggereableDescendantEntities<private>()<transacts>:void= for: DescendantEntity : Entity.FindDescendantEntities(entity) DescendantEntityComponent : DescendantEntity.GetComponents() CastToTriggerable := triggerable[DescendantEntityComponent] CastToTriggerable.PuzzlePiece? do: set TriggerableEntities += array{DescendantEntity}Добавьте функцию
DisableTriggerableComponentsдля отключения всех активируемых компонентов в дочерних модулях.Verse# Disable puzzle pieces DisableTriggerableComponents<private>():void= for: DescendantEntity : Entity.FindDescendantEntities(entity) DescendantEntityComponent : DescendantEntity.GetComponents() CastToTriggerable := triggerable[DescendantEntityComponent] CastToTriggerable.PuzzlePiece? CastToEnableable := enableable[DescendantEntityComponent] do: CastToEnableable.Disable()Добавьте функцию
IsPuzzleSolved, которая определяет, находится ли головоломка в состоянии решённой. Это делается путём перебора всех ранее найденных дочерних модулей с компонентом, реализующим интерфейсактивируемых компонентов, с проверкой, помечен ли связанный модуль как деталь головоломки и находится ли компонент модуля, реализующийактивируемыйкомпонент, в состоянии решения.Verse# Decides whether puzzle is solved IsPuzzleSolved<private>()<decides><transacts>:void= for: TriggerableEntity : TriggerableEntities TriggerableEntityComponent : TriggerableEntity.GetComponents() CastToTriggerable := triggerable[TriggerableEntityComponent] CastToTriggerable.PuzzlePiece? do: CastToTriggerable.InSolvedState[]Добавьте функцию
HandlePuzzleSolvedдля выполнения всех необходимых действий после того, как будет определено, что головоломка решена. Сюда входит настройка поляРешённаядля данного класса, отключение активируемых головоломкой компонентов на основе поля классаDisablePuzzleTriggerablesКогдаSolvedи передачаpuzzle_solved_eventвниз по иерархии Scene Graph.Verse# Handle all necessary actions once puzzle is known to be solved HandlePuzzleSolved<private>():void= set Solved = true if (DisablePuzzleTriggerablesWhenSolved?): DisableTriggerableComponents() Entity.SendDown(puzzle_solved_event{})Затем добавьте функцию
CheckPuzzleSolution. Это асинхронная функция-оболочка для определения того, решена ли головоломка с помощьюIsPuzzleSolved; если она решена, она также вызываетHandlePuzzleSolvedдля выполнения необходимых действий после решения головоломки.Verse# Async wrapper for determining whether puzzle is solved CheckPuzzleSolved()<suspends>:void= Sleep(0.25) if (not Solved?, IsPuzzleSolved[]): HandlePuzzleSolved()Добавьте переопределение функции
OnReceiveкласса компонента Scene Graph.Verse# Handle triggered events sent through the Scene Graph hierarchy OnReceive<override>(SceneEvent:scene_event):logic= if (TriggeredEvent := triggered_event[SceneEvent], TriggeredEntity := TriggeredEvent.TriggeredEntity?): spawn{CheckPuzzleSolved()} true falseДобавьте вызов в
InitializeTriggerableDescendantEntitiesв функциюOnBeginSimulationкомпонента.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() InitializeTriggereableDescendantEntities()
Следующие шаги
Далее создайте компонент «Триггер» и активируемые компоненты, реализующие интерфейс активируемых компонентов.
Окончательный код Puzzle.verse
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Verse.org/SceneGraph }
using { Logging }
puzzle_solved_event<public> := class(scene_event){}
# Scene Graph component handling puzzle component triggered events and when the puzzle is solved.
puzzle_component := class<final_super>(component):