大福未来研究所

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

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

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

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


*第4回、いよいよ譜面を叩く時。
というわけで前回の続きです。
前回の記事では、譜面が流れてくるところまでが実現できました。
今回は、それに入力に対応し、判定を取れるようにしましょう。

叩く基準、それが判定ライン

まずは判定ラインを作ります。これはあくまでも見せかけのためのものですから、
適当なキューブを伸ばしてライン上にすれば良いかと。
f:id:dfk_ohnuma:20171208005723p:plain

これで判定ラインが出来ました。
あっさりすぎるだろ。
あと、全てのシーケンスラインBPのX座標を、判定ラインの線に合わせて下さい。その位置を基準にして譜面は配置されていきますので、
ここに合わせていないとジャストのタイミングで判定ラインと重ならなくなります。

情報を登録していくスタイル

というわけで、次に判定用の処理を考えましょう。
シーケンスラインに並べられたオブジェは、原則として一番手前側にあるものから処理されていきます。
配列で言えばその時の0番目ですね。
入力があった際、比べる先は配列の0番目、そして内容は、
「入力があった時点の楽曲開始からの経過時間」と「該当オブジェに登録された時間」を比較すれば良いわけです。
それではAddNoteイベントを拡張してみましょう。
f:id:dfk_ohnuma:20171208010432p:plain
譜面を配置すると同時に、NoteArrayという配列型変数へ、
オブジェへのリファレンス、オブジェの登録時間、オブジェのタイプをそれぞれ突っ込みます。
オブジェのタイプについては、今はまだロングノートの事を考えないようにするために、一切気にしないでおいてください。

これで、譜面が配置されると同時に譜面が配列へ突っ込まれるようになりました。
このNoteArrayはNoteInfoStructという構造体変数を配列にしたものです
f:id:dfk_ohnuma:20171208011908p:plain
これで、シーケンスラインごとにオブジェを配列にして管理することが出来るようになりました。

また、楽曲の開始前にすこしオフセットを取りたい場合(ゲームメイン画面に入って2秒ぐらいしてから開始したい、とかそういう場合)
f:id:dfk_ohnuma:20171208020327p:plain
こうやって、配置場所にオフセットを足してやって下さい。


登録した情報は使ってなんぼ

というわけで、入力された際にNoteArrayの一番上のオブジェの情報を参照することで、
入力に対して判定を取ることが出来ますね。
それでは早速、そのためのマクロを作ります。
現在の時間と、NoteArrayの一番上の要素の時間とを比較し、差し引きした値を判定に使うために返します。
f:id:dfk_ohnuma:20171208012321p:plain
これの絶対値が小さいほど、正確なタイミングで入力されたということになります。
ここで戻り値を絶対値にしないのは、見逃しMISSを判定できるようにするためです。

これを使って、さっそく入力用の処理を作りましょう。
f:id:dfk_ohnuma:20171208012513p:plain
判定用の変数はPerfect、Great、Good、Bad、Missと5種類ありましたが、
Great判定を採用するのを辞めたのでこうなってます。
判定の数や基準とする判定タイム幅については自由に決めてみて下さい。

見逃したらダメ、ゼッタイ。

更に見逃しMISSを実装しましょう。
シーケンスラインのTickの最後尾に、見逃しミス用の判定を付け足します。
f:id:dfk_ohnuma:20171208014728p:plain
先程のマクロを絶対値ではなく、見逃したときだけ判定が成立するように使っているのがわかりますね。

起承転結

さてこれで判定は対応できましたが、ここで大事なものを付け足さないといけません。
それは「終わり」です。
曲がいつ終わるのかを情報としてゲーム側へ渡せないと、
いつまでもゲームが続いてしまいます。


なので、まずは譜面に終了用のコマンド「END」を追加しましょう。
f:id:dfk_ohnuma:20171208015010p:plain
コマンドEND:引数1…到達したら終了する小節数


そして、このコマンドをSequenceloaderが読めるようにしてあげます。
f:id:dfk_ohnuma:20171208015404p:plain
そこから伸びるピンはここへつなぎます。
f:id:dfk_ohnuma:20171208015835p:plain
あとは終了時間を超えていないかチェックすることで、
自動的に楽曲終了→リザルトへの移行が出来るようになります。
f:id:dfk_ohnuma:20171208015930p:plain


レベルはこうやってタイトル・セレクト・ゲームメイン・リザルトの4つを作っておけば、
簡潔なゲームであれば最低限のゲームとしての遷移は出来ると思います。
f:id:dfk_ohnuma:20171208020049p:plain

ついでにちゃんと動いているかどうか確認するためにウィジェットも作りましょう。
f:id:dfk_ohnuma:20171208021920p:plain
こうやってテキストブロックを用意して、まず最初にGameInstanceのリファレンスを用意して
f:id:dfk_ohnuma:20171208022034p:plain
それから、それぞれのテキストブロックの内容について関数をバインドさせてやればよいでしょう。
f:id:dfk_ohnuma:20171208022140p:plain

とりあえず、ここまでの状態で譜面を流してみて、
入力をちゃんと取れるかを確認してみましょう。

t.co
まだ爆発などは用意してませんが、タイミングよく入力すればオブジェが消えてくれるはずです。
次回はゲームとしてタイトルからリザルトまでを回せるように整えていきます。

最後に

これで入力に対して判定を取ることが出来るようになりました。
この時点ですでに、音ゲーとしての遊び方を用意することは出来ました。音は鳴ってないけど。
次回はタイトル画面や選曲画面やリザルト画面をとりあえず作って、ゲームとしての体裁を整えていきます。

以上で今回の記事は終わりです。お疲れ様でした。
アドカレの翌日の記事も私です(というか25日まで全部私です)。よろしくお願いします。

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

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

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


*第3回、いよいよ譜面が動く時。
というわけで前回の続きです。
※前回の記事に訂正点がありましたので、まだ確認してない方は前回の記事を再度確認して下さい。


シーケンスラインが出来た、
譜面も配置できた、
となれば次は、譜面を流してみるところからですね。


譜面が流れるようにする、と言っても、前回の記事を見れば分かる通り、
今回は「シーケンスラインActorそのものが移動することで、その子供になっているオブジェも揃って移動する」という仕組みにしています。
ですので、やるべきことは「シーケンスラインを動かす」ということですね。

現在、シーケンスラインはこのような構成になっていました。
f:id:dfk_ohnuma:20171205013108p:plain
ということはScene1を動かせば、その下にあるNoteたちは全て動いてくれます。
曲が始まったかどうかを判断するIsPlayingというbool型変数を用意して、組んでみるとこうなります。
f:id:dfk_ohnuma:20171207022852p:plain
BaseVelocityは前回も出てきた基本秒速です。
これにDeltaSecondsと-1をかけているので、Scene1とそこにひっついたオブジェたちは秒間(-基本秒速)だけX方向に移動します

もちろん、プレイ中かどうかを示すフラグが出来た以上は、
f:id:dfk_ohnuma:20171207023101p:plain
曲開始時の処理もお忘れなく。

これで、何らかのボタンで6レーン分のStartSongを呼び出してやることで、

t.co
このように、奥から手前まで譜面が流れてくるようになりました。


それでは次に、プレイヤーが入力する部分を作ります。


入力はキーバインド

f:id:dfk_ohnuma:20171207024201p:plain
まずはインプット用のBPを作ります。
これを使って……

f:id:dfk_ohnuma:20171207024248p:plain
まず全てのシーケンスラインを取得して、配列SeqLineへ入れます。
6つのシーケンスラインにそれぞれ「Line1~Line6」みたいな感じでタグを付けておいて、それを引っ張ってきています。
そうすることで順番通りに配列に突っ込めるはずです。


次に入力ですが、今回は直接キー入力イベントを作るのではなく、
キーバインド」を使ってみましょう。
キーバインドは、「Aキー」とか「ゲームパッドAボタン」とかのキー入力イベントの代わりに、
「攻撃ボタン」などの自由な名前で入力イベントを作り、それに対応するキーを登録することで、
「AキーかゲームパッドAボタンで攻撃」という場合に「攻撃ボタン」イベントだけで処理を作ることが出来たりする便利な機能です。
こうして書いていてもよくわからないと思うので、コチラをご覧ください。


「プロジェクト設定→インプット」で出てきます。
f:id:dfk_ohnuma:20171207024744p:plain
ここの「アクションマッピング」を開いて
f:id:dfk_ohnuma:20171207024823p:plain
このように好きな名前のインプットイベントと、
それに対応させるキーの登録を行います。


こうすることで、ブループリントの中で
f:id:dfk_ohnuma:20171207024923p:plain
先程登録したキーバインド用のインプットイベントを生成することが出来るようになります。


これを使うことで、キーボードでもゲームパッドでも同じイベントを呼べるようになりますし、
何かの事情があって攻撃ボタンなどに割り振るボタンが変更されたとしても、
BP上では攻撃ボタンのイベントはそのままにしておけるのです。


というわけでそれぞれのラインへ入力通知を送る用に組みました。
f:id:dfk_ohnuma:20171207025144p:plain
ここにある「PushKey」「ReleaseKey」イベントは、
シーケンスラインのアクタの中に作ったカスタムイベントです。
f:id:dfk_ohnuma:20171207025352p:plain


ここから判定のシステムを作っていくわけですが、
今日の部は一旦ここでおしまいです。

最後に

キーバインドを活用することで、複数のデバイス入力に対応させることが出来ます。
これはぜひ覚えておくと良いと思います。
今回で譜面が奥から手前へ流れるようになりました。
いよいよ次は入力とそれに対する判定の部分です。
ここができれば音はまだ鳴らないけど音ゲーらしさは出てくると思います。

今回の記事はここまでです。お疲れ様でした。
明日(と言っても今日ですが)は第4回です。
よろしくお願い致します。

【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回、譜面を実際に曲に合わせて動かすところから始まります。
どうぞ宜しくお願いします。

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

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

音楽ゲームって難しいんでしょ?

最初にこの記事を開いた時、そう思われた方は多いのではないでしょうか。
んなこたーない
色々とめんどくさいですが、それでも作るのがそこまで難しいわけではありません。
ゲームエンジンを使って作った場合、音を鳴らすまでがラクラクでできるので、
むしろとっとと作ってしまうことができます。
だってほら、
togetter.com
こんなの作ってたわけですし。
大丈夫、いけるいける!!
というわけで、この「土日で音ゲー作ろう」をやったときの流れを、
一週間に分けて解説します。
自己流で色々汚かったり力技だったりする部分もありますが、どうかお付き合いしていただけると嬉しいです。
今日は第一回です。


今回の音楽ゲームは、極力シンプルな作りにするために、
以下のような仕様にしてあります。
・6レーン
・1曲1譜面
・キー音はない
・曲のテンポは最初から最後まで一定とする

第1回、それは音ゲーの譜面の仕組みを考える時。

最初にするべきことは何でしょうか。
まずはどんな見た目の音ゲーにするかを考えるときですよね。
私は6レーンの奥から手前にオブジェが飛んでくるタイプ、つまり王道of王道音ゲーにすることを選びました。

ではその次は?
メイン画面を作るべきでしょうか。それとも……?


私はまず、譜面の仕組みを作ることにしました。

音ゲーの譜面って実際どうなのさ

まず音ゲーの譜面を作る側と、動かす側で考えてみたいと思います。


動かす側、つまりゲームシステム側からすれば、
譜面オブジェ(以降オブジェと言います)に必要なのは
・どの時間に叩くものか
・どのレーンか
が必要です。


逆に、譜面を作る側からすれば、
オブジェを置く際にx.xx秒とかy.yyy秒だなんてめんどくさい書き方をすると、
頭がこんがらがってきてしまいます。
ですから、譜面を作る側にとって必要な情報は
・テンポがいくつの、何小節目の何分の何拍目か
・どのレーンか
ということにすればよいのです。

そして、その橋渡しをするために譜面データを作り、それを読み取る仕組みを作れば良いのです。

構造体を作ろう→データテーブルも作ろう

というわけで、まずは譜面データの核になる構造体を作ります。
譜面データは譜面の位置だけが書かれていても意味がありません。
曲の名前や、テンポや、wavファイルによっては開始地点からどれだけずらすかなども記録しておく必要があります。
というわけでこのような構造体を作りました。
f:id:dfk_ohnuma:20171203232428p:plain
3つの文字列変数。「コマンド」「引数1」「引数2」です。
コマンドによってその行の役割を設定し、引数1と引数2はコマンドごとの内容になります。
この構造体を元にして、譜面のデータテーブルを作ります。
f:id:dfk_ohnuma:20171203232653p:plain
今回の譜面データには、以下のようなコマンドが使えるようにしたいと思います。


TITLEコマンド:引数1で曲名を、引数2でアーティスト名を表記する
GENREコマンド:引数1でジャンル名を表記する 引数2はどうでもいい
BPMコマンド:引数1でテンポを表記する 引数2はどうでもいい
(数値)コマンド:(数値)小節の(引数1)レーン目に(引数2)の通りにオブジェを配置する

この、譜面配置コマンドにおける引数2の文字列について説明します。

譜面配置の文字列の意味

これは、いわゆるBMS形式と呼ばれる音楽ゲームの譜面フォーマットに似たものになっていますが、

・文字列のうち、0が休符、1が音符。
・文字列の文字数で1小節を分割して、0のところには何も置かずに1のところにだけ音符を置く。

というルールです。
例えば「1」だけだと小節の頭にオブジェが一つ設置されます。
「1111」だとオブジェが4分音符間隔で設置されます。
「11111」だと、オブジェが5分音符(めったに使わなそう)間隔で設置されます。
「1011」だと、「1111」の2つ目の音符がなくなります。

わかってきたでしょうか?
この方式を使うことで、複数の拍子が混ざりあうような複雑なタイミングでも、細かいタイミングでも、
その小節に入る譜面の分母の最小公倍数だけ文字列を長くすることで、表現することができます。

それでは、この譜面テーブルを解読するためのBPを作ります。

譜面を読み込む仕組みを作ろう

というわけで、
f:id:dfk_ohnuma:20171203232752p:plain
まあまず、こんな感じにしました。
譜面データの全部の行をチェックし、その列を分解して、最初のコマンド部分に入っている文字列でスイッチします。
この時、曲の名前やアーティスト名、ジャンル名、テンポ数値を何処かに表示させたいこともあるかもしれないので、
それらの値を保存しておこうと思います。GameInstanceを使いましょう。
f:id:dfk_ohnuma:20171203234038p:plain
なんとまあ乱暴な変数名だ


そしてこのGameInstanceをゲームに設定しましょう。
f:id:dfk_ohnuma:20171203234149p:plain
こんな感じで設定。


そしてその中に変数を用意しておきます。
f:id:dfk_ohnuma:20171203234223p:plain
上から、
曲名、アーティスト名、ジャンル名、テンポ、パーフェクト数、グレート数、グッド数、バッド数、ミス数、最大コンボ、そして得点です。
で、そこに色々保存していきます。
f:id:dfk_ohnuma:20171203233905p:plain
こんな感じ。ジャンル名、曲名、アーティスト名、テンポは保存できるようになりましたね。

更に、
f:id:dfk_ohnuma:20171203234427p:plain
「Make Note」なる関数を作りました。
中身は……おっと今日はここまで!!


今回は序章なのでここまでです

ということで結構スピーディに譜面を読み込む仕組みを作ってましたが、
ちょっとあっという間過ぎたでしょうか?もし速すぎてもうちょっと細かく説明を……ということがあれば、
私のツイッター等へご連絡下さいませ。


というわけで、今日の記事はここまでです。お疲れ様でした。
明日は第二回、譜面配置のシステムづくりです。

【UE4】BPをキレイにしよう:折りたたみ編

この記事は、「ひとりUE4Advent Calendar 2017」の1日目の記事です。
qiita.com



前回はコメント編として、
dfkfuturelab.hatenablog.com
このような記事を書きましたが、今回は折りたたみ編です。

折りたたみってなんだ

ブループリントで処理を書いていくと、どんどんイベントグラフの使用面積が大きくなっていきます。
これはこれで確かにめんどくさいのです。
f:id:dfk_ohnuma:20171201235527p:plain
前回のラストに貼ったこのスクリーンショットも、見やすくなったものの、一つ一つの処理を見ていこうとするとやはり大きいと言わざるをえないでしょう。

折りたたみには種類がある

試しに折りたたみたいノードを範囲で囲って、右クリックしてみると、こんなのが出てきました。
f:id:dfk_ohnuma:20171202195228p:plain
この赤く囲んだところが折りたたみ処理です。
「ノードを折りたたむ」
「関数に折りたたむ」
「マクロに折りたたむ」
この3つの処理から、その場その場にあったものを選ぶ形になります。


関数とマクロの違いはコチラで紹介する3つのブログ
UE4 関数とマクロの違いについて 凛(kagring)のUE4とUnityとQt勉強中ブログ
katze.hatenablog.jp
unrealengine.hatenablog.com
をぜひご一読ください。

ノードを折りたたむ場合

「ノードを折りたたむ」で折りたたむ場合、
f:id:dfk_ohnuma:20171202232353p:plain
このように新しいイベントグラフが生成され、そこに畳まれます。
しかし、これはイベントグラフであり、関数でもマクロでもないため
「複数個置くことができない(コピペしようとすると更に新しいイベントグラフが作られる)」
というところに注意してください。
そのため、「一つのイベントをまるまるくくってわかりやすくする」などの方法が良いかもしれません。
なので、今回は長かったイベント4つを折りたたんでみましょう。
f:id:dfk_ohnuma:20171202233648p:plain
こうなりました。この時点で、ブループリントを開いたときの見やすさはピカイチです。

関数に折りたたむ場合

(今回のBPでは関数にする予定の部分がないので、たたみません)
関数に折りたたむ場合は、先ほどとは違って新しい関数ノードが生成され、そこに畳まれます。
関数の一番の特徴は、関数内でローカル変数を持てるということです。
イベントグラフとは違い、作った関数はいくつもコピペして使うことが出来ます。
なので、何度も使いそうな部分は関数やマクロにすると良いかもしれません。
関数の中では、TimelineノードやLatentノードなど、一部のノードが使えないという制限がありますが、
代わりにPureフラグを立てることで実行ピンの接続を不要にできます
これは使い所を間違えると処理がすごいことになるので、ヒストリアさんのこちらのブログを参考にして、
使い所を見極めると良いと思います。
historia.co.jp


マクロに折りたたむ場合

マクロに折りたたむ場合も、関数と同様新しいマクロノードが生成され、そこに畳まれます。
これもいくつもコピペして使えます(というかそのための……というか……)
インライン化機能もついており、実行時にはノードが展開されるので、結局マクロの中身全部をいくつもコピペするような形になります。
そのため、関数とは違って内部で値を保存したり…というのには不向きです。
しかし関数とは違って複数の出力ピンを持てたりノードの制限がなかったりとメリットも多いです。
マクロを使う際は関数のように呼び出しを行うのではなく、実行時にマクロの中身がマクロの置かれた場所へ置き換えられて実行されるので、
速度的なコスト面でも良いことがあるそうです。
unrealengine.hatenablog.com
そのあたりのことはalweiさんのブログで書かれてますよー。


というわけで幾つかのものをマクロにしてみました。
f:id:dfk_ohnuma:20171203000326p:plain
「こういう処理するためのマクロです」というコメントがついていれば、何かその処理で問題が起きた時に、
すぐに確認することが出来ます。
こうして……
f:id:dfk_ohnuma:20171203000428p:plain
処理ごとにイベントグラフへ折りたたみ、マクロにできそうなところをたたんで、それぞれの処理にコメントを付けたのがこれです。
最初は全部のイベントがごった煮になってましたよね、覚えてますか?
f:id:dfk_ohnuma:20171201082143p:plain
↑元々はこれでしたね(自分の傷をえぐりまくるスタイル)

最後に

こうしてコメント付けと折りたたみを使って、スパゲッティを見やすいグラフに整形してみましたが、
何よりもこの作業、自分がめちゃくちゃ楽しくなることがわかりました。
見やすいBPを自分が作っている……という実感が、これほど気持ちいいとは。
皆さんも是非、ストレス解消にBP整形を!!


というわけでこの記事は終わりです。ありがとうございました。
明日は私の「UE4でシンプルな音ゲーを作ろう:その1」です。
明日からはシンプルな音ゲーをのんびり作っていく記事になりますので、よろしくお願いします。

【UE4】BPをキレイにしよう:コメント編

この記事は、「ひとりUE4Advent Calendar 2017」の1日目の記事です。
qiita.com


はじめに

以前、このような記事を書きましたが、
dfkfuturelab.hatenablog.com
あれからかなり年月も経ち、自分なりにコメントの付け方も変わってきたので、
改めてBP整形の中の「コメント付け」について、もう少し触れた記事を作ろうと思いました。
特に技術的なすごい話をするわけではありません。
どっちかというと考え方的な話になるので、よろしくお願いします。


何のためにコメントをするのか

これは普通のC++C#のコードでもあることですが、
自分一人しか見ることがなさそうなプロジェクトであってもコメントをするのはなぜなのか、と考える時、
私は2つの理由を考えました。


1:時と場合によっては自分以外が見ることになる可能性があるため
2:未来の自分が振り返りやすくするため


1はまさに、「L.F.O.」の移植において発生したことであり(ものすっごく恥ずかしかった)、
2はまさに、このブログを書いている時に発生しています。


例えばこのようなブループリントがあったとして(積極的に自分の古傷をえぐるスタイル)、
f:id:dfk_ohnuma:20171201082143p:plain
こんなことになっていては、例えこの画面の中で流用しやすく、他のプロジェクトでもぜひ使いたい処理があったとしても、
または新しい開発やバグの修正等で、把握しておきたい現行の処理があったとしても、
それを見つけることにすら一苦労することになるでしょう。


UE4のブループリントは、処理の流れを視覚的に見ることが出来ます。
一つのイベントの流れを1画面で見渡せるということは、コードで言うと数十行以上のものを1つの画面で表示できるということです。
ですから、上手にコメントをつけることで、コードにつけるコメント以上に見やすさや分かりやすさを向上することが出来ます。
例えば先程のBPの中で、
f:id:dfk_ohnuma:20171201232350p:plain
こうして一箇所コメントを入れるだけで、
f:id:dfk_ohnuma:20171201232510p:plain
全体図からでも、
1.「この位置にどんな処理をするイベントが置かれているか」がわかる
2.「プレイヤーのリファレンスを登録するイベントがどこにあるか」がわかる
この2つの、それぞれ違う目的における捜査について、大きな恩恵を得ることが出来ます。
これはつまり、「.cppのすべての行が1つの画面に表示される中で、どこで何が行われているのかがおおまかに理解できる」というようなものです。
何て素晴らしいんでしょう!!

整列とコメントの実践例

それでは、先程のBPを「左から右、上から下」の原則に基づいて整列します。
f:id:dfk_ohnuma:20171201234509p:plain
さて、この時点でも相当綺麗ですね?
しかしこれでは小さすぎて、どこで何が行われているのかがちっともわかりません。
なので、コメントを付けていきましょう。
コメントは、コメントを付けたいノードたちをドラッグで囲って、Cキーで配置できます
今回は、このコメント欄の色分けをしてみましょう。


コメント欄は作ったときには白色ですが、
f:id:dfk_ohnuma:20171201234859p:plain
ここのComment Colorをいじることで色を変更できます(画像の場合は赤色になってます)

適当に色を振り分けるだけでもいいのですが、今回は更に、色の振り分けにルールをつけてみましょう
これは自己流ですので、皆さんも自分流の色の振り分けを試してみてください。


まず最初にイベントの色分けです。このイベントは何をしている、というのが先程の「プレイヤーのリファレンスをセットする」などの単純なものであれば、
その変数やオブジェクトを示す色(アクタなら水色、floatなら緑色など)を割り振ります。
一言で言えない系、もしくは何をいじってるのかが単純じゃない系のイベントは真っ赤にしましょう。イベントノードの象徴色です。

さて、この作業をこなしてみた結果……
f:id:dfk_ohnuma:20171201235527p:plain
こうなりました。見やすい!!


この後は、お好みに合わせてイベント内の処理に対して、その処理が扱っている変数やオブジェクトを示す色を使って色分けします。
細かくしすぎるとかえって見づらくなるので、そこのバランスは何度もコメントを作って覚えていくと良いと思います。

最後に

たかがコメント、されどコメント。
こうやって一つ一つのコメントを作っていくことで、BPは見やすくなります。
それは他人にとっても、未来の自分にとっても、非常に有益なことだと思います。
いつか自分が作ったBPを見た人への、ささやかなおもてなし、思いやりの気持ちでコメントをつけると、
その結果はいつか自分にフィードバックされると思います。


以上でこの記事は終わりです。お疲れ様でした。

明日は私による「BPをキレイにしよう:折りたたみ編」です。

【UE4】Unreal Engine 4.16 PreviewのGranular Synthを触ってみる

お久しぶりです。なんとか元気にやってます。

さて、UE4.16のプレビュー版が出てからしばらく経っていますが、なんとUE4にSynthesisプラグインなる新しいプラグインが登場し、
これを適用するとUE4の中でシンセサイザーを操作することが出来るようになりました!!

f:id:dfk_ohnuma:20170516022619p:plain
現時点ではこのように、
・「Modular Synth」
・「Granular Synth」
・「Synth Sample Player」
の3種類が追加可能になっています。(また凄いチョイスですねこれ)

このうち「Modular Synth」については、既に国内でもMozPacaさんによるブログ記事や、
mozpaca.hatenablog.com
株式会社プラスシグナルの大久保さんによるブログ記事
www.plus-signal.com
など、既に触れ始めている方がちらほらいらっしゃいます。
実際に私も触ってみましたが、ゲームエンジン内でシンセを触るという初めての感覚がとても面白く、
これをゲーム内でコンテンツとして落とし込めるようになるまでは時間がかかりそうだと思うものの、
シンセサイザーのパラメータをインタラクティブにゲーム側から反映させる事が出来るようになるのはとても大きな魅力であると感じました。
将来、UE4のシンセサイザー機能を利用したゲームが生まれるまではそう遠くないと思いますし、
いつまでたっても出ないなら私が作ってると思います。

というわけでGranularSynthってなんなんだ

それでは本題に入ります。今回私が触ってみたのは「Granular Synth」コンポーネントです。
ラニュラーシンセってなんぞや?と思う方も多いと思いますが、
DTMにおいてはグラニュラーシンセは結構な数が存在しており、
アンビエントやドローン、ノイズ等の領域では使っている方も多いかと思います。

今回はまず、グラニュラーシンセってなんぞやという話からしてみようと思います。

Granular、と入れてGoogle検索すると「粒状」と翻訳されて出てきます。
「偏ったDTM用語辞典」さんの記事を引用しますと、
偏ったDTM用語辞典 - グラニュラーシンセシス:Granular Synthesisとは - DTM / MIDI 用語の意味・解説 | g200kg Music & Software
シンセサイザーの波形合成方式の一つ。 元の音を数mSec~数十mSec程度の非常に細かな粒子(グレイン)に分割し、再配置する事で新たな音を合成する。」
とあります。

つまりグラニュラーシンセというのは、元の音を粉々にして再配置して発音するというシンセサイザーなのです。
このため、元の音から別物と言ってもいいような出音になったりすることも多く、
飛び道具的な使い方をしたり、あるいは実験音楽などにも使われたりしやすいシンセサイザーです。

さっそくUE4で使ってみよう

それでは4.16Preview版のエディタを立ち上げて、Third Personなりなんなりのテンプレから新しいプロジェクトを作ってみましょう。
名前は「SynthTest」とかでいいと思います。
そして、新しいActor Blueprintを作っておきましょう。
f:id:dfk_ohnuma:20170516025204p:plain
テスト用のプロジェクトですので、適当に「SoundActor」みたいな名前を付けておきました。
このアクタに、コンポーネントを追加してみます。
f:id:dfk_ohnuma:20170516022619p:plain
このように「コンポーネントを追加」からグラニュラーシンセを追加しましょう。
ついでに、シンセの効果を実感するためにAudio Componentも一つ作っておくとよいです。

f:id:dfk_ohnuma:20170516025451p:plain
(またひっどい名前)

さて。このグラニュラーシンセ、なんとコンポーネントの詳細画面を開くとSynth Sample Playerとほぼ同じ項目しか見えません。
ラニュラーシンセとしての本来の項目(グレインの長さやらどこから切り取るかやら)というのはBP上でいじるしかないのが現状です。
このプラグインはまだ仮実装だと思われるので、将来的にシンセの各パラメータへのアクセスは改善されるのではないかと思います。

Granular Synthコンポーネント周りのノードはこんな感じのものが並んでいます。
f:id:dfk_ohnuma:20170516075347p:plain


・Note On/Off……いわゆる鍵盤を弾く・離す(Modular Synthとほぼ同じ感じ)

・Set Attack Time…シンセのアタック時間を設定
・Set Decay Time…同じくディケイ時間を設定
・Set Sustain Gain…同じく、サステイン音量の設定
・Set Release Time Msec…同じく、リリース時間の設定
これら4つの項目は、シンセの「ADSR」と呼ばれる4項目の設定になります。
興味がある方は、是非ネットで調べてみると良いと思います。

・Set Sound Wave…ベースになる音をセットする
ラニュラーシンセは元になる音があってナンボなので、必須ですね。

・Set Scrub Mode…スクラブ再生モードの可否の設定
「スクラブ再生」というのは、偏ったDTM用語辞典さんでこのような説明がありますので御覧ください。

・Set Playback Speed…グレインの再生速度を設定する
・Set Playhead Time…グレインの再生開始位置を設定する。「現在の再生開始位置地点からずらす」「ファイルの先頭からずらす」の2種類が選べる

・Set Grain Duration…グレインの長さの基準と分布範囲を設定する
・Set Grain Envelope Type…グレインのエンベロープの種類を設定する
・Set Grain Pan…グレインのパンの基準点と分布範囲を設定する
・Set Grain Pitch…グレインのピッチの基準点と分布範囲を設定する
・Set Grain Probability…グレインの分布率を設定する。下がれば下がるほど音が歯抜けになる
・Set Grain Volume…グレインの音量を設定する
・Set Grains Per Second…秒間いくつのグレインを鳴らすか設定する
以上がグレインの設定になります。これらはTickなどからでも呼び出せるので、リアルタイムに音に変化をもたせることが出来ます。

Start/Stopはいいとして、他の関数はだいたいこんな感じのようです。
(間違ってたら突っ込んでやってください)

そんなわけで、さっそくブループリントで並べてみましょう。

f:id:dfk_ohnuma:20170516081127p:plain
Tickで毎フレームごとにシンセの設定を変えてやりながら

f:id:dfk_ohnuma:20170516081147p:plain
別々のボタンで元の音とシンセの音を鳴らせるようにします。

実際に鳴らしてみた

実際に起動して鳴らしてみたのがこれです。

元の音から全く別物になったのがわかると思います。
もちろん、設定次第ではそこそこ元の音に近いものが出せるようになったりもします。
(今回がかなり極端な例なので……)

まとめ

ラニュラーシンセは音をぶつ切りにして、新しい音に再構成するシンセです。
それにより変化する音の幅はとても大きく、これをうまくゲームと組み合わせることができれば、
新しいインタラクティブサウンドの形が提示される日も遠くはないでしょう。
今まで「シンセサイザーってなんだ 音楽ってなんだ」って思っていた方も、
この機会にゲーム側からシンセをいじってみるのに挑戦してみるのはありだと思います。
是非みなさんも触ってみて、そして良ければ記事を書いたりして知見を共有していただけるととても嬉しいです(`・ω・´)

以上でこの記事は終わりです。ありがとうございました。