このチュートリアルの最終ステップでは、コードを改善する方法を紹介しつつ、Verse の重要な考え方もあわせて学んでいきます。
Verse コードを改善する
このページでは、コード変更をステップごとに案内します。作業内容を確認したい場合は、最終結果として「完全なコード」セクションを参照してください。
リファクタリングとは、既存のコードの挙動を変えずに、設計や実装を改善するためにコードを再構築するプロセスです。 リファクタリングの主な目的は次の通りです。
変数名、スペース、コード全体の構造を改善して可読性を向上させること
挙動の実装をよりシンプルあるいは効率的にしてパフォーマンスを向上させること
類似した関数を 1 つにまとめたり、目的や型が似た複数の変数を配列などのコンテナーにまとめたりして、重複やコードの肥大化 (不要に大きく複雑なコード) を減らすこと
これらの目標に沿ってリファクタリングを行うことで、保守性、可読性、再確認性が高く、さらに将来的に挙動を拡張しやすいコードを書くことができます。 ゲームを本当にレベルアップさせられるのです。
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 --- #>
ターゲット クラスのラッパーと配列
コードを整理する際のもう一つの重要な目標は、重複を最小限にすることです。 現在の実装では、各 GoodTarget と BadTarget が独自のコールバックとヒット フラグを定義しており、コードが繰り返されています。
より良い方法は、個々のターゲットに必要な全てを含むラッパー クラスを作成することです。 シューティング レンジ マネージャーは、このターゲット ラッパーを配列で管理できるため、各コンポーネントを個別に定義する必要がなくなります。
これにより、重複が減るだけでなく、拡張性も向上します。 追加のコードを書くことなく、好きなだけターゲットを追加できます。
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メソッドを変更し、配列をループして GoodTargets とBadTargets を初期化します。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メソッドを変更し、GoodTarget 配列をループしてコンボ達成を確認します。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?): returnResetComboメソッドを更新し、GoodTarget 配列をループします。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 配列に 3 つの要素を追加し、それぞれを対応するターゲットに設定します。 任意で、個々のターゲットのスコア値を変更することもできます。
BadTargets 配列に 3 つの要素を追加し、それぞれを対応するターゲットに設定します。 また、任意で、個々のターゲットのスコア値を変更することもできます。
他の全てのプロパティが想定どおりに設定されていることを確認します。
応用編
このセクションはここで終了ですが、作業を続けることもできます。 Verse のさらなる機能やゲームプレイについては、「ゲームの仕組みを学ぶ」のドキュメントを参照してください。