大福未来研究所

大福フューチャーラボのなんか色々なアレ。プログラミング(C++/DirectX/Unity/UE4あたりやりたい)とか音楽とかの。

【UE4】UE4でシンプルな音ゲーを作ろう:その2

この記事は、「ひとりUE4 Advent Calendar 2017」の12/4担当記事です。
qiita.com

(あくまでも音ゲーとしての実装は自己流のものですので、
実際はもっと効率のいい組み方があったりすることもあると思いますが、
そういう場合は是非ブログ等でその技術をシェアしていただけるととても助かりますので
何卒よろしくお願いします……)

第2回、それは譜面を解読する回。

というわけで前回の続きです。
前回は譜面用のデータテーブルを解読するためのBPを作る途中で終わりましたね。
f:id:dfk_ohnuma:20171205010032p:plain
こんな感じで。



それではこのMakeNote関数は今どうなっているかといいますと、
f:id:dfk_ohnuma:20171205010126p:plain
まだ空っぽです。



だって、Note(オブジェ)をMake(作る)といっても、
どこに作るねん!!!って状況じゃないですか!


というわけで、このMakeNote関数を使って譜面を設置するための、
譜面レーンを用意しましょう。
実際のゲーム画面をやっと作り始めることになります。


シンプルでいいので、メイン画面を作る

だいたいPlateを引き伸ばす感じでいいので、作ってみます。
f:id:dfk_ohnuma:20171205010526p:plain
こんな感じに左右に1枚ずつ板を用意して


マテリアルをいじって(自作マテリアルです、普通はテクスチャ書くなり、キューブを引き伸ばして棒を作るなりなんなりしてレーンの仕切りを作ればいいと思います)
f:id:dfk_ohnuma:20171205010601p:plain


このように3ラインに見えるようにして
f:id:dfk_ohnuma:20171205010727p:plain


というあっさりした作業の結果がこれです。
f:id:dfk_ohnuma:20171205010813p:plain


これについて凄く雑な書き方をしているのは、
板置いて仕切り置くだけでいいからです。
特にこの部分に技術的なTipsになりうるものはないので、皆さんも各々のやりやすい形で作ればいいと思います。

今回の主役ことオブジェを作る

そしてオブジェ用のBPを作るわけですが、
今回はActorを作るのではなく、ActorComponentを作ります
この理由は後々説明します。

※おわび
当初ここで作るオブジェBPはアクタコンポーネントであると書いておりましたが、
一度上手く行かなかった時の作り方でした。
土日で制作したときも、結局はオブジェBPもアクタで作っておりましたので、
訂正しお詫び申し上げます。
正しくはこのようなアクタBPを作りました。

f:id:dfk_ohnuma:20171207021321p:plain



こうして新しくオブジェ用アクタが作られます。
このアクタはオブジェとして表示されるものを想定しているので、
f:id:dfk_ohnuma:20171205011306p:plain
こんな光る直方体を用意してみました。
特にこのBPにはイベントなどを持たせることもなく、編集はここで一旦終わります。

譜面をどうやって動かすか?

さてこれで譜面オブジェができました。
これを画面内に置いて移動させるわけですが、
実際にどうやって移動させるべきでしょうか。
一つ一つのオブジェに、移動量を設定して毎フレーム移動させる、それも良いかもしれませんが、
そうなるとオブジェの数だけTickなりなんなりが回ることになります。

それはそれでなんだか重いですし、
そもそもシーケンスラインに置かれたオブジェたちは全てが同じ速度で動くわけです。
つまり、同一ライン上のオブジェは全て、同じ動きをするわけです。


……ということは、
ライン用Actorの子供Actorとしてオブジェを設置して、
ライン用Actorを移動させるようにすれば、
子供であるオブジェたちも一斉に移動することになります。

イメージとしては、縄の上にオブジェを貼り付けて縄を引っ張ったら、貼られてるオブジェも一緒に引っ張られているような感じだと思ってもらえると嬉しいです。

レーン用のアクタを作ろう

というわけでシーケンスラインのアクタを作りましょう。
f:id:dfk_ohnuma:20171205012644p:plain

そして、Noteという名前のシーンコンポーネントを作ります。
f:id:dfk_ohnuma:20171205013108p:plain
そうしたら、このアクタの中に譜面配置用のイベントを作ります。

f:id:dfk_ohnuma:20171205013230p:plain
・イベントAddNote
  NoteTime:そのノートが配置されるであろう時間(譜面データから読み取ったもの・それについての処理は後述します)
  Type:ロングノートとか使いたい人用の拡張用引数 今は使わない


そして、この中の実装です。コメントを見れば何をしてるかはわかると思います。
f:id:dfk_ohnuma:20171205013457p:plain
この「基本秒速」というのは、オブジェが秒間どれぐらいの速度で動くようにしたいかの数値ですので、任意で決めて下さい。

まずこれで1つのラインが出来上がったので、ライン用Actorをレベル内に配置して、譜面ロード用のBPの変数にラインへのリファレンス変数SeqLineを作って登録してみましょう。
f:id:dfk_ohnuma:20171205013817p:plain
(仮処理だけどね)
複数のラインを用意するのであれば、SeqLineは配列にする必要が出てきます。
ラインの順番が正しく配列に組み込まれるよう、タグをつけるなりなんなりして工夫する必要があるので、気をつけて下さい。


ちなみにこの「LoadSequence」というイベントは前回から作っていた「譜面のデータテーブルを読み込むイベント」のことです
(前回イベント名とか書くの忘れてました、ごめんなさい)

それでは、いよいよライン上への譜面配置を行います。

譜面が設置される時間を計算するには?

譜面が設置されるための時間を計算するには、「その小節の頭までの時間」と、「小節の頭からどれぐらいの時間ずれるのか」が分かればいいですよね。
「その小節の頭までの時間」は、「1小節にかかる時間」×「小節数」で求められます。
「小節数」は譜面設置用コマンドと同値ですので、既に求めることが可能になっています。
となると、あとは「1小節にかかる時間」を求めることが必要ですね。
そこにはテンポが必ず必要になります。

1小節の時間を求めるために、このような処理を用意します。
f:id:dfk_ohnuma:20171205014442p:plain
そして譜面ロード用BPに1小節にかかる時間を入れておく変数、MeasureTimeを作り、
テンポを設定する際についでに計算するようにします。
f:id:dfk_ohnuma:20171205014544p:plain
これでMakeNote関数を働かせるための準備は揃いました。

いざ、オブジェ配置へ。

譜面配置コマンドの引数の仕組みについては前回も説明しましたが、
文字数がそのまま1小節の分割数になります。
譜面が配置される時間は、

譜面が配置される時間=該当小節の頭までの所要時間(A)+小節内の時間オフセット(B)

でしたね?

A=1小節あたりの所要時間(MeasureTime)×現在の小節数(譜面配置コマンド)
B=1小節あたりの所要時間(MeasureTime)÷小節の分割数(引数2の文字数)×現在の文字が何番目か(引数2の何文字目か)

というわけで、譜面が配置される時間はここまで用意した変数たちによって求めることが可能となりました。

実装前に、
f:id:dfk_ohnuma:20171205015447p:plain
ライン数を6つに増やしておきました。SeqLineへの登録の部分を書き換えて、変数も配列にしておく必要があります。

f:id:dfk_ohnuma:20171205015339p:plain


これで、譜面を配置する関数が実装できました。


*実際に見てみよう
f:id:dfk_ohnuma:20171205015622p:plain
先程も言いましたがBaseVelocityをいじって基本秒速を決めておきます。
これがオブジェごとの間隔をきめることにもなります。
f:id:dfk_ohnuma:20171205015801p:plain
譜面はこんなのでしたね?
譜面設置コマンド「1」の引数1が「0」を指してるので、
1小節目(曲自体は0小節目から始まります)の0レーン目にオブジェが設置されます。
BeginPlayかなにかで譜面ロード→設置を行われるように適当に組んで、
テストしてみましょう。


f:id:dfk_ohnuma:20171205015944p:plain
やったぜ。


更に譜面をちょっと書き換えてみましょう。
f:id:dfk_ohnuma:20171205020018p:plain
これで複数のラインに譜面が置かれるようになるのがわかるでしょうか?


そしてテスト。


f:id:dfk_ohnuma:20171205020055p:plain
勝ったッ!第2回完ッ!!!

今回はここまで

というわけで今回は譜面が読み込まれ、画面内に表示されるところまでを作りました。
今回も急ピッチだったかもしれませんので、もしわからないところなどありましたら
お気軽にTwitterなどで質問してみてくださいね。


今日はここまでです。お疲れ様でした。
明日(というか今日)は第3回、譜面を実際に曲に合わせて動かすところから始まります。
どうぞ宜しくお願いします。