【UEFN】UEFNのVerseでオブジェクト指向開発を行う(Verseの学習⑪)
[:contents]
Verseとオブジェクト指向
UEFNが登場して数か月が経過して、自分として検証を進めてきましたが、Verseはオブジェクト指向でバリバリとコーディングが行えるプログラミング言語という印象を持っています。
自分としてのコーディングのやり方がなんとなく固まってきたため、今回は、Verseで行うオブジェクト指向プログラミング(以下OOP)の入門的な内容をご紹介します。
対象としては、あくまで「OOPで開発を行っていない入門者向け」の内容になりますので、中上級者の方は、優しい目で、「あー、リンゴはこんな感じですかぁ」程度に読んでいただければと思います😇
簡単なサンプルをOOPを行わない場合とOOPを行った場合でコードを比較して解説していきます。
解説サンプル
次のようなシーンの作成を考えます
- 3つボタンが存在する
- それぞれのボタンを押した際に、押したボタンに応じたプロップが押したボタンの上に出現する
これをそれぞれ、OOP未適用な場合と、OOP適用した場合で紹介していきます。
OOP未適用なVerseコード
まず、最初に、OOP的ではなく、愚直にコーディングした場合です。(さすがにここまで愚直にコーディングする人はいないと思いますが・・・)
コードとしては、このようになります。
using { /Fortnite.com/Devices } using { /Verse.org/Simulation } using { /UnrealEngine.com/Temporary/Diagnostics } using { /UnrealEngine.com/Temporary/SpatialMath } oop_test_device := class(creative_device): @editable Button1 :button_device = button_device{} @editable Button2 :button_device = button_device{} @editable Button3 :button_device = button_device{} @editable NumberPropAsset1 : creative_prop_asset = DefaultCreativePropAsset @editable NumberPropAsset2 : creative_prop_asset = DefaultCreativePropAsset @editable NumberPropAsset3 : creative_prop_asset = DefaultCreativePropAsset OnBegin<override>()<suspends>:void= Button1.InteractedWithEvent.Subscribe(OnButton1Interacted) Button2.InteractedWithEvent.Subscribe(OnButton2Interacted) Button3.InteractedWithEvent.Subscribe(OnButton3Interacted) return OnButton1Interacted(Agent :agent) : void= Position := Button1.GetTransform().Translation + vector3{X:= -500.0, Z:= 100.0} SpawnProp(NumberPropAsset1, Position, rotation{}) return OnButton2Interacted(Agent :agent) : void= Position := Button2.GetTransform().Translation + vector3{X:= -500.0, Z:= 100.0} SpawnProp(NumberPropAsset2, Position, rotation{}) return OnButton3Interacted(Agent :agent) : void= Position := Button3.GetTransform().Translation + vector3{X:= -500.0, Z:= 100.0} SpawnProp(NumberPropAsset3, Position, rotation{}) return
ボタンの数だけ、Subscribeを実施し、関数もそれぞれに準備しています。
コード自体は簡単ですが、似たコードが重複しており、保守性が非常に低いコードとなっています。 UEFNのエディター上ではこのように設定することになります。
では次に、ボタンを押したらPropを発生するという機能を一つのクラスとしてまとめ、OOP的な改善をしたコードを紹介します。
OOPを適用したVerseコード
まず、ボタンを押したらPropを発生するという部分をprop_buttonクラスとして定義します。いろいろなやり方が考えられますが、今回はこのクラスの中にEditor上から編集可能な、ButtonDevice用の変数と、CreativePropAssetを設定するための変数を用意することとしました。
prop_button<public> := class<concrete>: @editable Button :button_device = button_device{} @editable NumberPropAsset : creative_prop_asset = DefaultCreativePropAsset Initialize<public>() :void= Button.InteractedWithEvent.Subscribe(OnButtonInteracted) return OnButtonInteracted(Agent :agent) : void= Position := Button.GetTransform().Translation + vector3{X:= -500.0, Z:= 100.0} SpawnProp(NumberPropAsset, Position, rotation{}) return
Initializeという部分にクラスの初期化部分(コンストラクタに相当する部分)を準備しています。Subscribe関数はこのInitialize関数の中に入れてしまっています。
Verseにもコンストラクタと呼ばれるクラスのインスタンスを準備するための機構が準備されていますが、グローバル関数として準備しなくてはならいため、自分としては使い辛く感じており、こうした関数を準備しています。(Verse的には正しくないかなと思います)
ボタンを押した際の動作を定義するOnButtonInteracted関数もこのクラス内に入れています。
UEFNにアトリビュートとして出せるように、クラスはconcreteになっていなければなりません。
この機能を使用するデバイスのメイン部分は以下のようになります。
oop_test_device := class(creative_device): @editable PropButtons : []prop_button = array{} OnBegin<override>()<suspends>:void= for(PropButton : PropButtons): PropButton.Initialize() return
OnBegin時にfor分でボタン数だけ、Initializeを行っています。 ボタン機能をクラスに分けたことで、それぞれのボタンに対する処理を書く必要がなくなりました。 先ほどのコードに比較して、シンプルな見通し手の良いコードになったのではないかと思います。
UEFNでの設定はこのような形になります。
UEFN上では、PropButtonsのボタンを配列として追加していくことができるため、より多くのボタンにも対応でき、汎用性も高まっています。
まとめ
今回はオブジェクト指向プログラミング入門として、機能をクラス分けする簡単な例を紹介しました。
クラス分けしたものは別ファイルに記述することができるようになるため、1ファイルとしてのコード量も少なくなり、OOP的な開発ルールに従うことで、保守性が高く、再利用性が高く、バグの発生しやすい開発が可能になるのではないかと思います。
VerseでOOP的な開発を行う方法に関しては、まだまだ語ることがあるため、今後も別の機会で紹介できればと思います。
(ただ、内容的にどんどん人を選ぶものになってしまうかも・・・😓)
UEFN関連の投稿がかなりたまってきたため、UEFN投稿のまとめページを作ってみました。
ぜひほかの記事も見ていただけると嬉しいです。
RingoGamesではUEFNに関するさまざまな情報を発信していきます。Twitterでお知らせしていきますので、よろしければ、Twitterのフォローをしていただけると幸いです。
Twitterはこちら