Verseでエイム練習用プロップを作る
前回 のサンプルを発展させ、Verseを使用して、ダメージを受けた際にランダムに移動するプロップを作っていきます。
今回の最終系はこのような形になります。

Suzanneモデルが射撃を受けるたびにランダムな方向に移動していきます。
エイム練習などに使用できるのではないかと思います。
実装方法
現状のVerseでは、動きに関する機能が存在するのはCreativePropだけでした。ただ、CreativePropは、ダメージを受けるという判定ができないようです。(CreativePropでダメージをEventとして受け取れる方法がご存じの方いれば教えてください)
そこで、
- ダメージ判定は、前回同様TriggerDeviceで
- 移動はCreativePropで
という少しトリッキーな実装をすることにしました。
シーン準備
上記の理由から、まず、Fortniteのプロップライブラリから適当なものをシーンに一つ配置します。 自分はBearのプロップを使用しました。(どちらにしろこれは表示には使用しないためなんでも良い)

次にTriggerDeviceをシーンに配置します。 シーンに配置後、TriggerDeviceをBearの子供にします。Outliner上でTriggerDeviceをBearにドラッグアンドドロップすれば子供にできます。
このような見え方にアウトライナ上でなっていれば親子付けされています。親子付けされていれば、親のベアーが移動するとその子供のTriggerDeviceも連動して移動します。

前回と同様にそれぞれのオブジェクトは以下のように設定していきます。
- Bear
- アクタ->Can be Damage をOFFに(ダメージを受けて壊れないように)
- StaticMeshComponent のレンダリング->visible をOFFに(表示しないように)
- Trigger
- ユーザーオプション->ゲーム中に表示をOFFに
- StaticMeshComponentのスタティックメッシュコンポーネントを外部から読み込んだSuzanneモデルに
- StaticMeshComponentのマテリアルはMI_Steel_Brightを今回は選択。
- ※メッシュとマテリアルはお好みで適当なものにしてください。
基本的なシーン構成はこれで完成です。
Verseコード完成形
では、Verseのコーディングを行っていきます。 前回同様、新規のVerseコードをCreativeDeviceを継承する形で作成します。 今回のコードの完成形はこのような形となりました。
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
## vector3 や rotation に必要
using { /UnrealEngine.com/Temporary/SpatialMath }
## random に必要
using { /Verse.org/Random }
# A Verse-authored creative device that can be placed in a level
aim_game_manager := class(creative_device):
@editable
RootProp : creative_prop = creative_prop{}
@editable
TargetMoveOffset : float = 100.0
@editable
TargetMoveTime : float = 0.5
@editable
TargetTrigger : trigger_device = trigger_device{}
# Runs when the device is started in a running game
OnBegin<override>()<suspends>:void=
TargetTrigger.TriggeredEvent.Subscribe(OnTriggeredEvent)
OnTriggeredEvent(Player:?agent):void=
## 現在位置の取得
CurrentLocation := RootProp.GetTransform().Translation
## ランダムで-TargetMoveOffsetから+TargetMoveOffsetまでの移動距離を与える
MinV := TargetMoveOffset
MaxV := -TargetMoveOffset
localX := GetRandomFloat(MinV, MaxV)
localY := GetRandomFloat(MinV, MaxV)
localZ := GetRandomFloat(MinV, MaxV)
var Position : vector3 = CurrentLocation + vector3{X:=localX, Y:=localY, Z:= localZ}
## 低すぎる、もしくは、高すぎる場合は初期位置に
if(Position.Z < 0.0 or Position.Z > 200.0):
set Position = vector3{X:=Position.X, Y:=Position.Y, Z:=100.0}
## Rotationの仮作成
Rotation : rotation = MakeRotationFromYawPitchRollDegrees(0.0, 0.0, 0.0)
## Propを動かす
spawn{RootProp.MoveTo(Position, Rotation, TargetMoveTime)}
コード解説していきます。 入力パラメーターの設定になります。Bearを入力するRootProp、TriggeerDeviceを入力するTargetTriggerの他、移動量(TargetMoveOffset)、移動時間(TargetMoveTime)を設定できるようにしています。これら4つのパラメータは後程Editor上で設定することになります。
@editable RootProp : creative_prop = creative_prop{} @editable TargetMoveOffset : float = 100.0 @editable TargetMoveTime : float = 0.5 @editable TargetTrigger : trigger_device = trigger_device{}
OnBeginの部分は前回と同一のため解説しません。
次にOnTriggeredEventの解説です。
この部分では現在のCreativePropの位置をまず取得したのち
CurrentLocation := RootProp.GetTransform().Translation
現在値に対して、X,Y,Zそれぞれの方向に-TargetMoveOffsetから+TargetMoveOffsetまでの間のランダムな量をオフセット値として加算します。
その値を次に向かう位置の座標とします。
最後に、PropをCreativePropの持っているMoveTo関数で移動させていますが、ここで注意点があります。
OnTriggeredDeviceは通常の関数なのですが、MoveToは非同期関数です。
Verseのルールの中で、通常の関数内で、非同期関数はそのまま使用することができません。
(非同期の話は、Verseのマニュアルのこちらを見ていただければと思います。詳細に解説されています。ただ、読むのには少し時間がかかりますが・・・)
そのため、spawnなどをつけて実行する必要があります。
spawn{RootProp.MoveTo(Position, Rotation, TargetMoveTime)}
これで、TriggerEventでランダムな位置に動くCreativeDeviceの完成となります。
最終シーンセットアップ
出来上がったCreativeDevice(この場合は、aim_game_manager という名前)をシーン上に配置し、以下のように設定します。
- RootPropは、Bearに
- TargetTriggerはBearの子供になっているTriggerに
- TargetMoveOffsetとTargetMoveTimeは適当なものを試してください。
これで実行すると、最初の画像のようにプロップが動くはずです。

まとめ
CreativePropがダメージを受けた時になんらかの処理をすることができないのかは、現在も調査中になります。これができればもっとスマートに組めるのですが・・・
次回以降でもう少しこれに色付けをして、ゲームらしくしていこうと考えています。
みなさんの何らかの参考になれば幸いです。
次回もよろしくお願いいたします。
今後もさまざまな情報を発信していきますので、Twitterフォローしていただけると嬉しいです。 twitter.com