В этом завершающем уроке вы узнаете, как доработать код, и по ходу освоите некоторые важные концепции Verse.
Улучшите свой код Verse
Здесь пошагово рассматривается процесс внесения изменений в код. Если вы хотите проверить свою работу, загляните в раздел Полный код, в котором вы сможете ознакомиться с окончательным результатом.
Реорганизация — это процесс, в ходе которого вы реструктурируете код, чтобы сделать его компактнее и удобнее или поменять логику работы без изменения выполняемых функций. Ниже приведены наиболее распространённые цели реорганизации кода:
улучшение читаемости за счёт более логичного именования переменных, размещения пробелов и изменения общей структуры кода;
повышение производительности за счёт более простой или эффективной реализации поведения;
уменьшение количества повторений и «раздувания» кода (когда некоторые его части становятся слишком большими, излишними или слишком сложными) путём объединения схожих функций в одну или объединения нескольких переменных одинакового типа и их перемещения в контейнеры, такие как массивы.
Реорганизация, осуществляемая с учётом этих целей, поможет вам написать код, с которым в будущем будет удобно работать и который не только будет более читаемым, но и предоставит больше возможностей для расширения и улучшения функционала. Выводите свои игры на новый уровень!
GetFirstPlayer()
Написание читаемого кода — отличная практика в программировании. К примеру, GetFirstPlayer() будет гораздо удобнее для понимания, чем GetPlayspace().GetPlayers()[0]. Кроме того, такой подход является наилучшей практикой для программирования распространённых операций, поскольку здесь мы чётко определяем цель операции.
Откройте файл
shooting_range_manager_device.verse.Добавьте метод
GetFirstPlayer.Обратите внимание, что метод
GetFirstPlayerимеет спецификаторы эффекта <decides><transacts>, поскольку он может завершиться с неоднозначным результатом и откатиться к первоначальному состоянию. Изучите статью Неоднозначность в Verse, в которой описаны выражения с неоднозначным результатом и допускающие неоднозначность контексты.Verse# Returns the first player in the playspace. GetFirstPlayer()<decides><transacts>:player= return GetPlayspace().GetPlayers()[0]Измените метод
AdjustScore, чтобы использовать наш новый методGetFirstPlayer.Обратите внимание, что метод
GetFirstPlayerвызывается с квадратными скобками, а не с круглыми, как раз из-за неоднозначного результата.Verse# Adjusts the player's score by the provided value. AdjustScore(Value:int):void= # Start the timer if it hasn't started yet. if (not IsTimerStarted?): StartTimer() # Sets the score award to the base value of the target multiplied by the current weapon level. ScoreManager.SetScoreAward(Value * CurrentWeaponLevel) <# --- New Code Start --- #>Измените метод
IncreaseWeaponLevel, чтобы использовать наш новый методGetFirstPlayer.Verse# Increases the player's weapon level by one (up to the maximum value). IncreaseWeaponLevel():void= if: # If able to retrieve the first player and current weapon level isn't maxed, then... <# --- New Code Start --- #> Player:player = GetFirstPlayer[] <# --- New Code End --- #>
Массивы и адаптеры класса мишени
Ещё одной ключевой целью при оптимизации кода является минимизация дублирования. В текущей реализации каждая «хорошая» и «плохая» мишень определяет свой собственный обратный вызов и флаг попадания, что делает код повторяющимся.
Здесь лучше будет создать класс-адаптер, который будет содержать всё, что необходимо каждой мишени в отдельности. Затем диспетчер тира сможет управлять этими адаптерами мишеней в массиве без необходимости определять каждый компонент по отдельности.
Такой подход не только позволит нам избежать дублирования, но и улучшит масштабируемость. Вы можете добавить столько мишеней, сколько захотите, без написания дополнительного кода.
Определите класс
good_target_wrapper. Выше вы можете разместить ваше определение классаshooting_range_manager_device.Verse# A wrapper class for the good targets to support array storage with a self-contained event callback. good_target_wrapper := class: @editable Target:shooting_range_target_track_device = shooting_range_target_track_device{} @editable Score:int = 100 # A circular reference to the shooting range manager device.Определите класс
bad_target_wrapper. Выше вы можете разместить ваше определение классаshooting_range_manager_device.Verse# A wrapper class for the bad targets to support array storage with a self-contained event callback. bad_target_wrapper := class: @editable Target:shooting_range_target_device = shooting_range_target_device{} @editable Score:int = -100 # A circular reference to the shooting range manager device.Добавьте следующие свойства массива к устройству диспетчера тира.
Verse@editable: GoodTargets:[]good_target_wrapper = array{} @editable BadTargets:[]bad_target_wrapper = array{}Удалите следующие элементы из вашего устройства диспетчера тира. Теперь ими занимаются классы адаптеров.
GoodTarget1-3
GoodTargetScore
BadTarget1-3
BadTargetScore
HitGoodTarget1-3
OnGoodTarget1-3Hit()
OnBadTarget1-3Hit()
Измените метод
OnBegin, чтобы инициализировать «хорошие» и «плохие» мишени, циклически перебирая массив.Verse# Runs when the device is started in a running game. OnBegin<override>()<suspends>:void= <# --- New Code Start --- #> # Initialize GoodTargets. for (GoodTarget : GoodTargets): GoodTarget.Init(Self) # Initialize BadTargets.Измените метод
CheckCombo, чтобы проверять завершение комбо, циклически перебирая массив «хороших» мишеней.Verse# If the combo is complete, enable the ComboTarget. CheckCombo():void= <# --- New Code Start --- #> # If any of the good targets are not hit, exit the function. for (GoodTarget : GoodTargets): if (not GoodTarget.IsHit?): returnОбновите метод
ResetCombo, чтобы циклически перебрать массив «хороших» мишеней.Verse# Resets the combo tracking variables, re-enables all GoodTargets, and disables the ComboTarget. ResetCombo():void= <# --- New Code Start --- #> for (GoodTarget : GoodTargets): GoodTarget.Reset() <# --- New Code End --- #>Сохраните код Verse и выполните его сборку.
Полный код
using { /Fortnite.com/Devices }
using { /Verse.org/Random }
using { /Verse.org/Simulation }
<#>
Utility Classes
<#>
# A wrapper class for the good targets to support array storage with a self-contained event callback.
good_target_wrapper := class:
Собираем воедино
Вам необходимо задать новые значения для изменённых редактируемых свойств в вашем устройстве Verse.
Выберите устройство shooting_range_manager_device в окне просмотра или на панели Структура.
На панели Сведения задайте следующие параметры:
добавьте три элемента в массив GoodTargets и привяжите их к соответствующим мишеням. При желании вы также можете изменить количество очков за каждую конкретную мишень;
добавьте три элемента в массив BadTargets и привяжите их к соответствующим мишеням. Теперь вы также можете по желанию изменить количество очков за каждую конкретную мишень;
убедитесь, что все остальные свойства заданы корректно.
Самостоятельная работа
Здесь мы подходим к завершению, но это не значит, что вам пора заканчивать. Ещё больше информации о различных возможностях Verse и игровом процессе представлено в разделе Изучение механик игры.