blog heroalche.studio

VerseをつかってPlayerごとのトリガを設定する

著者:

kazaumi

投稿日 2024.02.01更新日 2024.02.01

こんにちは!

UEFNでは仕掛けを使ってプレイヤーに対して様々なイベントを実行できます.

プレイヤーの状態によってイベントの制御をわけるとき, (UEFNの)クラスやチームを利用することでも実現可能です.

しかし,(UEFNの)クラスやチームには上限があり,かつその管理はプロジェクト全体に影響を及ぼしてしまいます.

ここでは,Verseを使うことで実装する方法を紹介します.

■大まかな仕組み

今回は条件を満たしたプレイヤーをテレポートさせる仕組みを作成します. 作りたい体験は次のようになります.

  1. プレイヤーがミューテーターゾーンを通過する
  2. ボタンを押すと,プレイヤーがミューテーターゾーンを通過していれば,そのプレイヤーがテレポートする
  3. ミューテーターゾーンを通過していないプレイヤーはボタンを押してもテレポートすることができない

■Mapをつかう

Mapというものを使えば,上のような仕組みをかんたんに実現することができます.

[Verse 言語のリファレンス]マップ

マップをつかうと,キーとなるプレイヤと一対一で様々な値を管理することができます. 今回は,ミューテーターゾーンに入るときにマップを使って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{} #テレポート先のデバイス

teleportsystemEdit

そして今回の要点である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を設定することもできるので,一度条件を満たしたプレイヤに対して,再び条件を満たさなくなるようにすることも可能です.