Infiltrator の不可視性によって、Infiltrator が Defender の目標のアイテムを持っているときに興味深い問題が引き起こされます。 Defender は、自分が目標とするアイテムを基地に持ち帰ろうとしている可能性のある不可視のプレイヤーを、どのようにして見つけることができるのでしょうか? この問題を解決するために、何らかのビジュアル エイド、この例では小道具を使って、Infiltrator の居場所を Defender に示すことができます。
以下の手順では、プレイヤーが目標のアイテムを持っているときに、プレイヤーの頭上に浮かぶオブジェクトを作成する方法を示します。
Item Capture Manager を作成する
- item_capture_manager という名前の新しい Verse の仕掛けを Verse Explorer で作成し、その仕掛けをレベルにドラッグします。
item_capture_managerファイルの冒頭に次を追加します。using { /UnrealEngine.com/Temporary/SpatialMath}を追加してvector3構造体にアクセスします。これを使用して、プレイヤーの頭上に浮かぶインジケータをどこにテレポートするかを取得します。using { /Fortnite.com/Characters}も追加して、プレイヤーのfort_characterにアクセスします。using { /Fortnite.com/Devices} using { /Verse.org/Simulation} using { /Fortnite.com/Characters} using { /UnrealEngine.com/Temporary/Diagnostics} using { /UnrealEngine.com/Temporary/SpatialMath}
item_capture_managerクラス定義に以下のフィールドを追加します。CaptureItemSpawnersという名前のキャプチャー アイテム スポナーの仕掛けの、編集可能な配列。この配列には、Infiltrator 用のキャプチャー アイテム スポナー仕掛けが保持されます。item_capture_manager := class(creative_device): Logger:log = log{Channel := triad_item_capture_log_channel} # キャプチャーするためのアイテムをスポーンするアイテム スポナーをキャプチャーします。 @editable CaptureItemSpawner:capture_item_spawner_device = capture_item_spawner_device{}CaptureItemIndicatorという名前の編集可能なクリエイティブ小道具。これが、Infiltrator が目標のアイテムを手に入れたときに Infiltrator の頭上に浮かぶ小道具です。# キャプチャーするためのアイテムをスポーンするアイテム スポナーをキャプチャーします。 @editable CaptureItemSpawner:capture_item_spawner_device = capture_item_spawner_device{} # CaptureItemSpawner のアイテムを保持している場合に、プレイヤーの # 頭上に浮かぶ小道具。 @editable CaptureItemIndicator:creative_prop = creative_prop{}MapIndicatorという名前の編集可能なマップ インジケータの仕掛け。これは、レベル内の CaptureItemSpawner の下に配置され、各チームの目標のアイテムがあるマップに表示されます。# CaptureItemSpawner のアイテムを保持している場合に、プレイヤーの # 頭上に浮かぶ小道具。 @editable CaptureItemIndicator:creative_prop = creative_prop{} # 各チームの目標のアイテムがあるマップに表示されるインジケータ @editable MapIndicator:map_indicator_device = map_indicator_device{}UpdateRateSecondsとVerticalOffsetの 2 つの編集可能な浮動小数値。1 つ目はCaptureItemIndicatorの位置がどれくらいすばやく変化するかを制御し、2 つ目はCaptureItemIndicatorがプレイヤーの頭からどれくらい離れて浮かぶかを制御します。# 各チームの目標のアイテムがあるマップに表示されるインジケータ @editable MapIndicator:map_indicator_device = map_indicator_device{} # CaptureItemIndicator がその位置を更新する頻度。 @editable UpdateRateSeconds:float = 0.15 # CaptureItemIndicator がプレイヤーの頭上を浮かぶ高さ。 @editable VerticalOffset:float = 180.0ItemGrabbedMessageDeviceという名前の編集可能な HUD メッセージの仕掛け。目標のアイテムがピックアップされた場合に、各プレイヤーにメッセージを送信します。# CaptureItemIndicator がプレイヤーの頭上を浮かぶ高さ。 @editable VerticalOffset:float = 180.0 # プレイヤーがキャプチャー アイテムを取得すると、メッセージを表示します。 @editable ItemGrabbedMessageDevice:hud_message_device = hud_message_device{}ScoreManagerDeviceという名前の編集可能なスコア マネージャーの仕掛け。プレイヤーが目標のアイテムをキャプチャーすると、チームにスコアを付与します。# プレイヤーがキャプチャー アイテムを取得すると、メッセージを表示します。 @editable ItemGrabbedMessageDevice:hud_message_device = hud_message_device{} # プレイヤーがキャプチャー アイテムを取得すると、スコアを付与します。 @editable ScoreManagerDevice:score_manager_device = score_manager_device{}ReturnTimeという名前の編集可能な浮動小数値。CaptureItemSpawner に戻す前の時間がキャプチャー アイテムにある場合、インジケータを CaptureItemSpawner に戻すタイミングを把握するため、その戻す時間の長さをトラックする必要があります。
- 新しい
FollowCharacter()メソッドをitem_capture_managerクラス定義に追加します。このメソッドはfort_characterを受け取り、プレイヤーの頭上に浮かぶインジケータを使ってそれらをトラックします。この関数に<suspends>指定子を追加します。プレイヤーが目標のアイテムを持っているときにいつでも、これらのいずれかをスポーンできるようにするためです。# CaptureItemIndicator がプレイヤーの頭上を継続的に追跡するようにします。 # CaptureItemIndictator の更新ループ、およびプレイヤーがアイテムをキャプチャするか、 # ドロップするか、撃破されるかの間でレースを行います。 FollowCharacter(FortCharacter:fort_character)<suspends>:void= Logger.Print("Spawned FollowCharacter function")
目標のアイテムを持ちながらレースを続ける
プレイヤーが目標のアイテムを手に入れたときにどうなるかを考えることが重要です。 プレイヤーは以下の行動を取ることができます。
- 動き回る。この場合は、CaptureItem およびマップ インジケータをプレイヤーの位置に継続的に更新する必要があります。これはループで処理できます。
- 目標のアイテムをキャプチャする。この場合は、インジケータが視界外のどこかの CaptureItemSpawner に戻されるようにする必要があります。このインジケータは、プレイヤーがキャプチャー アイテムを持たない限り可視にはならないためです。
- 目標のアイテムをドロップするか、撃破される。この場合、インジケータはアイテムがドロップされた場所に置かれたままになり、キャプチャー アイテムが戻される際に CaptureItemSpawner に戻されます。
これを実現するために race 式 を設定します。これらの 3 つの条件の間で race を使用することで、プレイヤーが目標のアイテムをドロップまたはキャプチャーするまで待機しながら、インジケータの位置を継続的に更新できます。
FollowCharacter()にrace式を追加します。CaptureItemSpawnerのItemCapturedEventのAwait()、CaptureItemSpawnerのItemCapturedDroppedEventのAwait()、およびFortCharacterのEliminatedEvent()のAwait()というloopの間で実行されるように race を設定します。FollowCharacter(FortCharacter:fort_character)<suspends>:void= Logger.Print("Spawned FollowCharacter function") race: loop: CaptureItemSpawner.ItemCapturedEvent.Await() CaptureItemSpawner.ItemDroppedEvent.Await() FortCharacter.EliminatedEvent().Await()loop内で、FortCharacterの位置を取得して、それをTransform変数に保存します。loop: Transform := FortCharacter.GetTransform()- 次に、
MoveTo()をスポーンし、前に設定したVerticalOffsetをTransformの 平行移動と回転に加えた位置に、CaptureItemIndicatorとMapIndicatorの両方を、UpdateRateSecondsの時間数だけ移動させます。Spawn{}の両方のMoveTo()関数を実行します。互いの式が完了するまで待機するのではなく、CaptureItemIndicatorとMapIndicatorの両方を正確に同じタイミングで移動させる必要があるためです。平行移動はX、Y、Zの座標から成るvector3であるため、VerticalOffsetを新しいvector3内で加える必要があります。VerticalOffsetはプレイヤーの頭上での垂直方向の距離であるため、それをvector3のZ値として設定します。loop: Transform := FortCharacter.GetTransform() spawn{CaptureItemIndicator.MoveTo(Transform.Translation + vector3{Z := VerticalOffset}, Transform.Rotation, UpdateRateSeconds)} spawn{MapIndicator.MoveTo(Transform.Translation + vector3{Z := VerticalOffset}, Transform.Rotation, UpdateRateSeconds)} - 最後に、
0.0秒間のスリープを行います。これにより、シミュレーションの更新 ごとに一度だけループが実行され、スポーンを行うMoveTo()関数が制御ができなくならないようにします。FollowCharacter()コードは次のようになります。# CaptureItemIndicator がプレイヤーの頭上を継続的に追跡するようにします。 # CaptureItemIndictator の更新ループ、およびプレイヤーがアイテムをキャプチャするか、 # ドロップするか、撃破されるかの間でレースを行います。 FollowCharacter(FortCharacter:fort_character)<suspends>:void= Logger.Print("Spawned FollowCharacter function") race: loop: Transform := FortCharacter.GetTransform() spawn{CaptureItemIndicator.MoveTo(Transform.Translation + vector3{Z := VerticalOffset}, Transform.Rotation, UpdateRateSeconds)} spawn{MapIndicator.MoveTo(Transform.Translation + vector3{Z := VerticalOffset}, Transform.Rotation, UpdateRateSeconds)} # このループは、シミュレーションの更新ごとに一度だけループが実行されるようにするため、ゲーム ティック 1 つ分だけスリープを行います。 Sleep(0.0) CaptureItemSpawner.ItemCapturedEvent.Await() CaptureItemSpawner.ItemDroppedEvent.Await() FortCharacter.EliminatedEvent().Await() Logger.Print("Objective dropped or captured")インジケータをリセットする
- キャプチャー アイテムがキャプチャーまたは戻された場合、インジケータを視界外のどこかの
CaptureItemSpawnerに戻す必要があります。その場合、CaptureItemSpawnerの上の高い位置にテレポートさせます。これを行うには、ReturnIndicators()という名前の関数をitem_capture_managerクラス定義に追加します。# マップおよびキャプチャー アイテム インジケータをスポナーの上の初期位置に戻します。 ReturnIndicators(InAgent:agent):void= CaptureItemSpawnerのトランスフォームを取得し、それをSpawnerTransform変数に保存します。次に、CaptureItemIndicatorおよびMapIndicatorのMoveTo()をスポーンし、CaptureItemSpawnerの平行移動と回転にVerticalOffsetを加えた位置に移動します (loopでCaptuerItemSpawnwerの上にこれらを配置したのと同様)。小道具を視界外の遠い位置に置きたい場合は、VerticalOffsetを大きな数 (たとえば「10」) で乗算できます完成したReturnIndicators()メソッドは次のようになるはずです。# マップおよびキャプチャー アイテム インジケータをスポナーの上の初期位置に戻します。 ReturnIndicators():void= SpawnerTransform := CaptureItemSpawner.GetTransform() # テレポートしてスポナーに戻り、CaptureItemIndicator および MapIndicator はマップの上の視野外で非表示にします。 spawn{CaptureItemIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds)} spawn{MapIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds)} Logger.Print("Returned Indicators to capture spawner")
プレイヤーによる目標のアイテムの取得、ドロップ、およびキャプチャーを処理する
- 新しい
OnItemPickedUp()メソッドをitem_capture_managerクラス定義に追加します。このメソッドはagentを受け取り、そのキャラクターのFollowCharacter()のインスタンスをスポーンします。# プレイヤーが目標のアイテムを取得すると、各プレイヤーに信号を送信します OnItemPickedUp(InAgent:agent):void= Logger.Print("Objective Grabbed") InAgentのFortCharacterを取得して、そのFortCharacterを使ってFollowCharacter()関数をスポーンします。完成したOnItemPickedUp()メソッドは次のようになるはずです。# プレイヤーが目標のアイテムを取得すると、各プレイヤーに信号を送信します OnItemPickedUp(InAgent:agent):void= Logger.Print("Objective Grabbed") if(FortCharacter := InAgent.GetFortCharacter[]): ItemGrabbedMessageDevice.Show() spawn{FollowCharacter(FortCharacter)}- 新しい
OnItemCaptured()メソッドをitem_capture_managerクラス定義に追加します。このメソッドは、目標のアイテムを取得したagentを取得します。# アイテムがキャプチャーされると、キャプチャーしているチームにスコアが付与され、インジケータを戻します。 OnItemCaptured(CapturingAgent:agent):void= Logger.Print("Objective Captured") OnItemCaptured()で、ScoreManagerDeviceを有効にしてキャプチャーしているプレイヤーのチームのスコアを付与し、ReturnIndicators()を呼び出してインジケータを戻します。# アイテムがキャプチャーされると、キャプチャーしているチームにスコアが付与され、インジケータを戻します。 OnItemCaptured(CapturingAgent:agent):void= Logger.Print("Objective Captured") ScoreManagerDevice.Activate() ReturnIndicators()- 新しい
OnItemDropped()メソッドをitem_capture_managerクラス定義に追加します。このメソッドは、アイテムをドロップしたagentを取得します。# プレイヤーがアイテムをドロップすると、ReturnTime が 0 より大きい場合に # WaitForReturn() 関数をスポーンします。 OnItemDropped(InAgent:agent):void= Logger.Print("Objective Dropped") - 目標のアイテムがドロップされた場合、インジケータは、目標のアイテムがピックアップされるか、
CaptureItemSpawnerに戻るまで目標のアイテム付近にとどまる必要があります。インジケーターが戻るタイミングを把握するには、先ほど設定したReturnTime変数を使用します。ReturnTimeが0.0に等しい場合は、その時間数だけ待機してから、インジケーターを戻します。ReturnTimeが負の数の場合、目標のアイテムは戻る時間がないため、インジケーターを動かす必要はありません。インジケータを動かして戻す場合は、次のステップで定義する、WaitForReturn()という名前の新しいヘルパー関数をスポーンします。# プレイヤーがアイテムをドロップすると、ReturnTime が 0 より大きい場合に # WaitForReturn() 関数をスポーンします。 OnItemDropped(InAgent:agent):void= Logger.Print("Objective Dropped") if(ReturnTime >= 0.0): spawn{WaitForReturn()} else: Logger.Print("The dropped objective does not return") - 新しい
WaitForReturn()メソッドをitem_capture_managerクラス定義に追加します。この関数は、ReturnTimeの時間数だけ待機し、待機が完了する前に目標のアイテムがピックアップされなかった場合にアイテムを戻します。このメソッドに<suspends>モディファイアを追加し、Sleep()の実行を許可します。# ReturnTime の時間数だけ待機し、インジケータを戻します。 WaitForReturn()<suspends>:void= Logger.Print("Waiting to return the indicators...") - インジケータを戻す必要があるか、または
ReturnTimeが終了する前に目標のアイテムがピックアップされることに依存しないか。ピックアップされた場合、インジケーターは即座にプレイヤーに戻されてしまって不自然なビジュアルになるため、戻さないようにします。これを解決するため、値がレースの結果に等しいロジック変数を使用します。# ReturnTime の時間数だけ待機し、インジケータを戻します。 WaitForReturn()<suspends>:void= Logger.Print("Waiting to return the indicators...") # 時間切れになる前にキャプチャー アイテムがピックアップされなかった場合、 # CaptureItem とマップ インジケータを戻します。 ShouldReturn:logic := race: WaitForReturn()関数は、2 つの条件の間でレースを行う必要があります。ReturnTimeがなくなり、目標のアイテムがCaptureItemSpawnerに戻った場合、インジケータを戻す必要があり、ShouldReturnはtrueになる必要があります。または、ReturnTimeの期限が切れる前に目標のアイテムがピックアップされた場合、ShouldReturnはfalseになる必要があります。これらの各条件が値を返すため、2 つの異なるblocksを使用してレースを実行します。ShouldReturn:logic := race: block: block:- 最初のブロックでは、
ReturnTimeの時間数の間だけSleep()を呼び出し、trueを返します。2 番目のブロックでは、CaptureItemSpawner.ItemPickedUpEventに対してAwait()を実行し、false を返します。これで、ShouldReturn変数は、これらのいずれかが完了すると初期化されます。ShouldReturn:logic := race: block: Sleep(ReturnTime) true block: CaptureItemSpawner.ItemPickedUpEvent.Await() false ShouldReturnが true の場合、インジケータを戻す必要があります。ShouldReturnがtrueと評価された場合、ReturnIndicators()を呼び出します。完了したWaitForReturn()コードは、次のようになるはずです。# ReturnTime の時間数だけ待機し、インジケータを戻します。 WaitForReturn()<suspends>:void= Logger.Print("Waiting to return the indicators...") # 時間切れになる前にキャプチャー アイテムがピックアップされなかった場合、 # CaptureItem とマップ インジケータを戻します。 ShouldReturn:logic := race: block: Sleep(ReturnTime) true block: CaptureItemSpawner.ItemPickedUpEvent.Await() false if(ShouldReturn?): ReturnIndicators()- 次に
OnBegin()で、CaptureItemSpawnerのItemPickedUpEventをOnItemPickedUp()に、ItemCapturedEventをOnItemCaptured()に、およびItemDroppedEventをOnItemDropped()にサブスクライブします。OnBegin<override>()<suspends>:void= CaptureItemSpawner.ItemPickedUpEvent.Subscribe(OnItemPickedUp) CaptureItemSpawner.ItemCapturedEvent.Subscribe(OnItemCaptured) CaptureItemSpawner.ItemDroppedEvent.Subscribe(OnItemDropped) SpawnerTransform := CaptureItemSpawner.GetTransform() - 最後に、
OnBegin()内で、CaptureItemIndicatorおよびMapIndicatorでMoveTo()を呼び出すことでスクリプトが実行された場合、開始位置にインジケータを配置します。OnBegin()コードは次のようになります。OnBegin<override>()<suspends>:void= CaptureItemSpawner.ItemPickedUpEvent.Subscribe(OnItemPickedUp) CaptureItemSpawner.ItemCapturedEvent.Subscribe(OnItemCaptured) CaptureItemSpawner.ItemDroppedEvent.Subscribe(OnItemDropped) SpawnerTransform := CaptureItemSpawner.GetTransform() # テレポートしてスポナーに戻り、CaptureItemIndicator をマップの下の視野外で非表示にします。 CaptureItemIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds) MapIndicator.MoveTo(SpawnerTransform.Translation + vector3{Z := VerticalOffset * 10.0}, SpawnerTransform.Rotation, UpdateRateSeconds) -
エディタに戻り、スクリプトを保存してビルドし、その仕掛けをレベル内にドラッグします。
CaptureItemIndicatorとして使用する適切な小道具を選択して、レベル内に取り込みます。この小道具は、明確に目に見えるものであれば何でもかまいません。この例では「Diamond (ダイヤモンド)」を使用します。[Details (詳細)] パネルで、CaptureItemSpawner を InfiltratorCaptureSpawner に、CaptureItemIndicator を選択した小道具に割り当てます。また、MapIndicator を Infiltrator のマップ インジケーターに、ItemGrabbedMessageDevice を Infiltrator の HUD メッセージの仕掛けに、および ScoreManagerDevice を Infiltrator のスコア マネージャーに割り当てます。ReturnTime を負の数に設定します。Infiltrator のキャプチャー アイテムは戻されないためです。Attacker 用に
item_capture_managerのインスタンスを設定する必要もあります。CaptureItemIndicator を Infiltrator の小道具とは異なる小道具に変更して、チームが混乱しないようにしてください。また、その他すべての仕掛けを割り当ててください。ReturnTime を正の数に設定します。Attacker のキャプチャー アイテムは設定された時間後に戻るからです。 - UEFN ツールバーの [Launch Session (セッションを起動)] をクリックし、レベルをプレイテストします。レベルをプレイテストすると、プレイヤーが目標のアイテムを持った際に、その頭上に小道具が現れるはずです。この小道具はプレイヤーとともに移動し、プレイヤーが目標のアイテムをドロップまたはキャプチャーすると、テレポートしてキャプチャー アイテム スポナーに戻ります。

次のステップ
このチュートリアルの 次のステップ では、ゲーム内で何をすべきかをプレイヤーにすばやく伝える方法と、プレイヤー体験を向上させる際に何に重点を置くべきかについて説明します。