こんにちは!
UEFNでは仕掛けを使ってプレイヤーに対して様々なイベントを実行できます.
プレイヤーの状態によってイベントの制御をわけるとき, (UEFNの)クラスやチームを利用することでも実現可能です.
しかし,(UEFNの)クラスやチームには上限があり,かつその管理はプロジェクト全体に影響を及ぼしてしまいます.
ここでは,Verseを使うことで実装する方法を紹介します.
■大まかな仕組み
今回は条件を満たしたプレイヤーをテレポートさせる仕組みを作成します. 作りたい体験は次のようになります.
- プレイヤーがミューテーターゾーンを通過する
- ボタンを押すと,プレイヤーがミューテーターゾーンを通過していれば,そのプレイヤーがテレポートする
- ミューテーターゾーンを通過していないプレイヤーはボタンを押してもテレポートすることができない
■Mapをつかう
Mapというものを使えば,上のような仕組みをかんたんに実現することができます.
マップをつかうと,キーとなるプレイヤと一対一で様々な値を管理することができます. 今回は,ミューテーターゾーンに入るときにマップを使ってlogic値を更新します. ボタンを押してテレポートしようとするときは,押したプレイヤーの状態をMapから確認し, もしもTrueになっていたらテレポートするようにします.
今回は少し拡張して,2つのトリガをもとにテレポートする仕組みで例を紹介します.
■サンプルコード
それではさっそくコードを紹介します.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
triggered_teleport_system := class(creative_device):
@editable
Zone_A : mutator_zone_device = mutator_zone_device{} #1つ目のトリガのデバイス
@editable
Zone_B : mutator_zone_device = mutator_zone_device{} #2つ目のトリガのデバイス
@editable
TeleportButton : button_device = button_device{} #テレポートを実行するボタン
@editable
DestinationTeleporter :teleporter_device =teleporter_device{} #テレポート先のデバイス
var ZoneTrigger_A:[player]logic = map{} #1つ目のトリガを管理
var ZoneTrigger_B:[player]logic = map{} #2つ目のトリガを管理
OnBegin<override>()<suspends>:void=
Zone_A.AgentEntersEvent.Subscribe(SetZoneTrigger_A) # 各デバイスへのインタラクションをサブスクライブ
Zone_B.AgentEntersEvent.Subscribe(SetZoneTrigger_B)
TeleportButton.InteractedWithEvent.Subscribe(TryTeleport)
SetZoneTrigger_A(Agent:agent):void =
if(Player:=player[Agent]): #Zone_A に侵入したら トリガーをTrueにする
if(set ZoneTrigger_A[Player] = true ):
SetZoneTrigger_B(Agent:agent):void =
if(Player:=player[Agent]): #Zone_B に侵入したら トリガーをTrueにする
if(set ZoneTrigger_B[Player] = true ):
TryTeleport(Agent:agent):void =
if: #PlayerのZone_AトリガがTrueかつZone_BのトリガもTrue
Player:=player[Agent]
ZoneTrigger_A[Player] = true
ZoneTrigger_B[Player] = true
then:
DestinationTeleporter.Teleport(Agent) # テレポートを実行
else :
Print("Player Can Not Teleport") # いずれかがfalseならテレポートしない
まず,トリガとなる2つのデバイスと,テレポート前後のデバイスをそれぞれ設定できるようにします.
@editableをつかうとUEFNのエディタ上で参照を取ることができるので,それぞれのデバイスと,このverseコードによって作られるデバイスをレベル上に配置し,このデバイスの4つの参照を埋めましょう
@editable
Zone_A : mutator_zone_device = mutator_zone_device{} #1つ目のトリガのデバイス
@editable
Zone_B : mutator_zone_device = mutator_zone_device{} #2つ目のトリガのデバイス
@editable
TeleportButton : button_device = button_device{} #テレポートを実行するボタン
@editable
DestinationTeleporter :teleporter_device =teleporter_device{} #テレポート先のデバイス

そして今回の要点であるmapを定義します.これはplayerをキーとしてlogic値を返します. 今回は2つのトリガを用意したのでmapもそれに合わせて2つ用意します.
var ZoneTrigger_A:[player]logic = map{} #1つ目のトリガを管理
var ZoneTrigger_B:[player]logic = map{} #2つ目のトリガを管理
OnBeginでは配置したデバイスにプレイヤがインタラクションした際のイベントをVerseに登録します.
今回はゾーンへの侵入時と,テレポートするためのボタンに触れた際のイベントを登録します.
OnBegin<override>()<suspends>:void=
Zone_A.AgentEntersEvent.Subscribe(SetZoneTrigger_A) # 各デバイスへのインタラクションをサブスクライブ
Zone_B.AgentEntersEvent.Subscribe(SetZoneTrigger_B)
TeleportButton.InteractedWithEvent.Subscribe(TryTeleport)
上で紐づけた関数の中身を定義します.
SetZoneTriggerでは侵入したプレイヤーをキーとしてmapをtrueにします. これによって,このミューテーターゾーンにインタラクションしたプレイヤーは,Trueという値が返るように対応付けされるようになります.
SetZoneTrigger_A(Agent:agent):void =
if(Player:=player[Agent]): #Zone_A に侵入したら トリガーをTrueにする
if(set ZoneTrigger_A[Player] = true ):
SetZoneTrigger_B(Agent:agent):void =
if(Player:=player[Agent]): #Zone_B に侵入したら トリガーをTrueにする
if(set ZoneTrigger_B[Player] = true ):
テレポートできるかどうかはすべてのトリガの値が有効であるかどうかで判定されます. if:のブロックのコードはすべてが失敗せずに正しい場合にthen:のブロックの内容が実行されます.
ミューテーターゾーンを通ってトリガが有効になっていないプレイヤは,対応が設定されていないことで実行が失敗するため,elseブロックの処理に進んでしまい,テレポートすることができません. 一方で,双方のミューテーターゾーンを通ってトリガのmapの対応が設定されているプレイヤはthen:ブロックの処理に進み,テレポートすることができます.
TryTeleport(Agent:agent):void =
if: #PlayerのZone_AトリガがTrueかつZone_BのトリガもTrue
Player:=player[Agent]
ZoneTrigger_A[Player] = true
ZoneTrigger_B[Player] = true
then:
DestinationTeleporter.Teleport(Agent) # テレポートを実行
else :
Print("Player Can Not Teleport") # いずれかがfalseならテレポートしない
出来上がったものがこちらです.最初のプレイヤーは2つのゾーンをくぐり,ボタンを押すとテレポートしています.続くプレイヤーはそのあとにボタンを押してもテレポートせず,先のプレイヤーと同様に2つのゾーンをくぐらなければテレポートできないようになっています.
■応用
今回はトリガにミューテーターゾーン,テレポートの実行にボタンデバイスを設定しましたが,これらは,Verseにプレイヤとのインタラクトイベントが公開されているデバイスであれば自由に変更することができます.
またmapの値はtrueだけでなくfalseを設定することもできるので,一度条件を満たしたプレイヤに対して,再び条件を満たさなくなるようにすることも可能です.