🔫

[UEFN][Verse]ObjectPoolで無限に湧くターゲットを作成する

2023/09/27に公開

概要


UEFNのVerseを使って無限に湧くターゲットを作成する方法を紹介します
頑張ればVerseを使わなくても実現できますが、Verseを使うを比較的簡単に作成することができます

ターゲットの作成

ターゲットのモデルはこちらを使いました
https://free3d.com/ja/3d-model/dartboard-v4--319212.html

UEFNに取り込んでBluePrintを作成していきます
建築小道具(Building Prop)を親クラスにして作成します

StaticMeshを追加し、先ほどインポートしたダーツのメッシュを設定します
正面に向けるためにX軸を90度回転させ、小さかったのでスケールを2倍にしました

なお、このモデルはマテリアルのエラーが出てしまったのでテクスチャだけ使うように修正しました

小道具操作機(Prop Manipulator Devices)の設置

作成したターゲットにダメージが入ったことを検知するため小道具操作機を設置します
Fortnite/Devicesの中から小道具操作機を選択しレベルに設置します
そのあとにゾーン内のすべてのオブジェクトに影響を与えるにチェックを入れゾーンの大きさを設定します

また、今回は(x,y,z)=(0,-1000,200)の位置に設置しました

さらにこの中にいくつかのターゲットを配置しておきます

武器の設置

ターゲットを破壊できるようにアイテムスポナーを使って武器を設置しておきます

Verseの記述

Verseを作成します
今回はobject_poolクラスとして作成しました


using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Fortnite.com/Characters }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath }
using { /Verse.org/Verse }
using { /Verse.org/Random }

object_pool := class(creative_device):

    @editable PropManipulator : prop_manipulator_device = prop_manipulator_device{}

    @editable TargetAssets : []creative_prop = array{}

    @editable Offset : vector3 = vector3 : 
        X := 0.0
        Y := 0.0
        Z := 0.0

    var index : int = 0

    #仮のスコア
    var score :int = 0

    #オブジェクトにダメージが入った時に呼ばれる関数
    OnDamaged(Agent : agent) : void=
        if(target := TargetAssets[index]):
            Rot := target.GetTransform().Rotation
            NewPosition := vector3{X:= 0.0, Y:= 0.0, Z:= -10000.0}
            #ダメージの入ったオブジェクトは地下に移動して見えないようにする
            if(target.TeleportTo[NewPosition,Rot]):
                # Indexがループするようにする
                set index += 1
                if(index >= TargetAssets.Length):
                    set index = 0
        
        #スコアを加算
        set score = score + 1
        Print("score : {score}")
            
        if(newTarget := TargetAssets[index]):
            #新しいオブジェクトの位置を決める
            Rot := newTarget.GetTransform().Rotation
            SpawnPoint : vector3 = vector3 : 
                X := GetRandomFloat(-200.0,200.0) + Offset.X
                Y := GetRandomFloat(-200.0,200.0) + Offset.Y
                Z := 100.0
            if(newTarget.TeleportTo[SpawnPoint,Rot]):

    # Runs when the device is started in a running game
    OnBegin<override>()<suspends>:void=
        Print("object_pool OnBegin")

        #1つ目以外は見えないようにする
        NewPosition := vector3{X:= 0.0, Y:= 0.0, Z:= -10000.0}
        for(X := 1..TargetAssets.Length):
            if(hideObject := TargetAssets[X]):
                Rot := hideObject.GetTransform().Rotation
                if(hideObject.TeleportTo[NewPosition,Rot]):

        #小道具操作機のDamagedEventに関数を登録する
        PropManipulator.DamagedEvent.Subscribe(OnDamaged)

ロジックの流れとしてはOnBeginで1つ目以外は地下に隠すのと、小道具操作機へのイベントの登録を行っています

小道具操作機のDamagedEventは小道具操作機の指定した範囲にあるオブジェクトにダメージが入った際にイベントが呼ばれます

OnDamaged関数の中ではダメージの入ったオブジェクトを地下に隠し、次のターゲットをランダムな位置に表示させています

Verseに参照を持たせる

小道具操作機、ターゲットの参照を持たせ、ターゲットが出現するオフセットを設定します

これで実行すると冒頭のGIFのように無限にターゲットが生成されます
今回は仮でScoreをログとして出力していますが、他の仕掛けに渡すことで様々なゲームに応用することができます

終わりに

VerseでObjectPoolを作成する方法を紹介しました
今回は1つずつしか表示しないロジックでしたが、少し改造すれば同時にいくつか同時に表示することもできます
また、敵キャラAIのような実装と組み合わせて敵が無限に湧いてくるようなシステムも作ることができると思います

Discussion