【UEFN/Verse/初心者向け】トリガーを押したらPropがプレイヤーについてくるDeviceを作ってみた
はじめに
とあるゲームの企画でプレイヤーがペットのような相棒を持たせるようにしたい、、というところからどのように実装するのか自分なりに考えてみました。
まだまだVerseに関する記事が少ないのでどんどん書いていきたいと思っています!
Verseの書き方
Verseエクスプローラーを開く
Verseエクスプローラーで右クリックしてAdd new...
を押す
deviceの名前を決め作成をクリックしVerseエクスプローラーから編集したいVerseファイルをダブルクリックするとVSCodeが開き編集できます!
本題
動作の映像になります。
とりあえずこれが全体コードになります。
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Fortnite.com/Characters }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/SpatialMath}
grab_device := class(creative_device):
@editable
target_props:creative_prop = creative_prop{}
@editable
grab_trigger:trigger_device = trigger_device{}
@editable
ungrab_trigger:trigger_device = trigger_device{}
var is_grab:logic = true
OnBegin<override>()<suspends>:void=
grab_trigger.TriggeredEvent.Subscribe(OnGrab)
ungrab_trigger.TriggeredEvent.Subscribe(UnGrab)
OnGrab(QAgent:?agent):void=
if(Agent := QAgent?; FortCharacter := Agent.GetFortCharacter[]){
set is_grab = true
spawn:
FollowProps(FortCharacter)
}
UnGrab(QAgent:?agent):void=
UnFollowProps()
FollowProps(fortChara: fort_character)<suspends>:void=
loop:
if (is_grab = true):
PlayerPosition : vector3 = fortChara.GetTransform().Translation
target_props.MoveTo(PlayerPosition, rotation{}, 1.0)
else:
break
UnFollowProps<public>():void=
set is_grab = false
意外とシンプル?かな。
個人的に知っておくと今後役に立ちそうなことを軽く書き出していきます。
@editable
について
これはUnityエンジニアならおなじみの[SerializeField]
と同等の機能を持つものです。
UEFNエディタで見てみると以下のようにエディタ上で実際のデバイスを変更したり数字をいじれるようになったりします。
OnBegin
について
こちらゲームが始まった一番最初に呼ばれる部分になります。今回はトリガーのイベント待ちが宣言されてますね。
trigger_device
の使い方
以下がtrigger_device
内のコードになります。
# Used to relay events to other linked devices.
trigger_device<public> := class<concrete><final>(trigger_base_device):
# Signaled when an `agent` triggers this device.
# Sends the `agent` that used this device. Returns `false` if no `agent` triggered the action (ex: it was triggered through code).
TriggeredEvent<public>:listenable(?agent) = external {}
# Triggers this device with `Agent` being passed as the `agent` that triggered the action. Use an `agent` reference when this device is setup to require one (for instance, you want to trigger the device only with a particular `agent`.
Trigger<public>(Agent:agent):void = external {}
# Triggers this device, causing it to activate its `TriggeredEvent` event.
Trigger<public>():void = external {}
# Base class for various specialized trigger devices. See also: * `trigger_device` * `perception_trigger_device` * `attribute_evaluator_device`
trigger_base_device<public> := class<abstract><epic_internal>(creative_device_base):
# Enables this device.
Enable<public>():void = external {}
# Disables this device.
Disable<public>():void = external {}
# Resets the number of times this device has been activated. This will set `GetTriggerCountRemaining` back to `0`
Reset<public>():void = external {}
# Sets the maximum amount of times this device can trigger.
# * `0` can be used to indicate no limit on trigger count.
# * `MaxCount` is clamped between [0,20].
SetMaxTriggerCount<public>(MaxCount:int):void = external {}
# Gets the maximum amount of times this device can trigger.
# * `0` indicates no limit on trigger count.
GetMaxTriggerCount<public>()<transacts>:int = external {}
# Returns the number of times that this device can still be triggered before hitting `GetMaxTriggerCount`.
# Returns `0` if `GetMaxTriggerCount` is unlimited.
GetTriggerCountRemaining<public>()<transacts>:int = external {}
# Sets the time (in seconds) after triggering, before the device can be triggered again (if `MaxTrigger` count allows).
SetResetDelay<public>(Time:float):void = external {}
# Gets the time (in seconds) before the device can be triggered again (if `MaxTrigger` count allows).
GetResetDelay<public>()<transacts>:float = external {}
# Sets the time (in seconds) which must pass after triggering, before this device informs other external devices that it has been triggered.
SetTransmitDelay<public>(Time:float):void = external {}
# Gets the time (in seconds) which must pass after triggering, before this device informs other external devices that it has been triggered.
GetTransmitDelay<public>()<transacts>:float = external {}
今回は一番使うTriggeredEvent
についてザックリ解説していきます。
TriggeredEvent
について
今回僕が書いたコードをもとに説明します。
OnBegin<override>()<suspends>:void=
grab_trigger.TriggeredEvent.Subscribe(OnGrab)
ungrab_trigger.TriggeredEvent.Subscribe(UnGrab)
OnGrab(QAgent:?agent):void=
if(Agent := QAgent?; FortCharacter := Agent.GetFortCharacter[]){
set is_grab = true
spawn:
FollowProps(FortCharacter)
}
UnGrab(QAgent:?agent):void=
UnFollowProps()
OnBeginで宣言しているから起動時にすぐ何かが起きるわけではありません。
例えるならゲーム開始時にトリガーが誰かに押されるのを監視し始めたという理解がいいかもしれません。
監視した状態で誰かがトリガーの上に行くとSubscribe
内のコードが呼ばれます。
今回はOnGrab
やUnGrab
が呼ばれてその中身のコードが呼ばれていくわけです。
注意してほしいのがSubscribe
内で宣言したメソッドの引数には絶対に?agent
を入れておかないとコンパイルエラーが起きます。 このagent
とはトリガーを押したプレイヤーそのものの情報が取得できる?という考えでいいかもしれません。
今回の例で行くとAgent
からフォートナイトゲーム上の情報を簡単にとるためのfort_character
クラスを取得してそのプレイヤーの位置情報を取得するということをしています。
if(Agent := QAgent?; FortCharacter := Agent.GetFortCharacter[]){
set is_grab = true
spawn:
FollowProps(FortCharacter)
}
FollowProps(fortChara: fort_character)<suspends>:void=
loop:
if (is_grab = true):
PlayerPosition : vector3 = fortChara.GetTransform().Translation
target_props.MoveTo(PlayerPosition, rotation{}, 1.0)
else:
break
参考にしたもの
プレイヤーにオブジェクトがついて来させる方法
agent
からfort_character
を取得する方法
【余談】これだけは理解しておいて損はないやつ<<関数エフェクト>>
Verseを書いていくうちにぶち当たるコンパイルエラー赤波線のたいていの原因はこれでした。
UEFN界隈盛り上げていくぞー
midra-lab.notion.site/MidraLab-dd08b86fba4e4041a14e09a1d36f36ae 個人が興味を持ったこと × チームで面白いものや興味を持ったものを試していくコミュニティ
Discussion