大福未来研究所

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

【VTuberとか】PCでエフェクトを掛けた音声をiPhoneの音声入力に突っ込む方法

新年最初の記事がコレなんですってよ。

バ美肉できた!はいいけれど……

こんにちは大福です。
皆さんはバ美肉という言葉をご存知でしょうか。
最近は、男性が可愛い女の子のアバターを身にまとい、ボイスチェンジャーを駆使して声まで女の子っぽくして
VTuberとして配信したり動画を作ったり、VRChatでイチャイチャニャンニャンしてるらしいですよ!

最近ではバーチャルキャラクターとなって配信できるプラットフォームとして、
SHOWROOM Vや、REALITY Avatarなどのサービスが登場し、スマホからでも気軽にバ美肉できるようになりました。

なりました。

が、
ボイチェン派にはここで大きな障害が立ちはだかっています。



スマホの音声入力にはそもそもボイチェンがないやんけ!!!!」


じゃあ無理やり繋いでみようぜ
というのがこの記事です。

環境構築

まず、ここまではすでに揃っていて、PC環境ではバ美肉出来ているものとして話を進めます。
・PC
・PC用オーディオインターフェース
・マイク(オーディオインターフェースに接続済み)
ボイスチェンジャー系エフェクト(PC内にインストール済み)


で、今回はスマホとして
iPhone 8 Plus
を使用します。


今回、この構成に追加するのは
スマホオーディオインターフェース
・あとケーブル類

以上です。実は超簡単。
でも多分、「スマホオーディオインターフェース」の世間的な知名度がとても低いんだと思います。

スマホオーディオインターフェースとは

外部からの音声入力や、外部への音声出力を扱う外部インターフェイスです。
これがあれば、質のいいマイクを繋いで高品質な配信を行ったりできます。
PC用のオーディオインターフェースとは違い、ドライバインストール等の必要はありません。

さっそく買ってみた

友人のNakajiくんがiRigHDを使ってスマホとVT-4を接続していましたが、
このiRig2もスマホ用インターフェースの一つです。
iRig2を使ってもいいですが、今回はTASCAM iXZを購入しました。

コレを使っても、VT-4とスマホの接続は可能です。


今回、TASCAM iXZを選んだ理由は以下のとおりです。
ボイスチェンジャーを使わない場合、直接コンデンサマイクを接続しても電池駆動でファンタム電源の供給ができる
・iRigシリーズと比べて安い(例:iRigHDはAmazonで実売10000円だが、iXZはヨドバシで3900円だった)
・レイテンシがiRigと比べて小さいような気がする(小並感)


では、繋いでみましょう。



コンデンサマイクから

オーディオインターフェースのマイクインプット(左側のやつ)に繋いで
マイクから入った音はPC内のエフェクターで加工されます。
これはインターフェースのOutputから出てきますから、

iXZのギター端子につなぎます。
もし、コンデンサマイクを直接つなぐ際はギター端子ではなくマイク端子へつなぎます。

↑ギター端子につないだ例

できあがり

あとはこれをiPhoneへ繋げば、ボイチェンした声が入力されてくれます。やったぜ。

自分の声の戻りを聴きたいときは、モニタヘッドホンをPC用のオーディオインターフェースにつなぎます。

スマホ用のオーディオインターフェースの出力は、モニタではなくスマホからの音が出てきます。

まとめ

繋ぐのは簡単だったし、スマホ用のオーディオインターフェースは安価なものも多いので、
モバイルVTuberでもボイチェン勢が増えてくれたらいいなと思いつつこの記事を書かせていただきました。
それでは今年もよろしくお願いいたします。
この記事はここまでです。お疲れ様でした。

【C95】2018年冬コミ:おしながき

最初に

えー、非常に告知が遅くなってしまい、ただただ申し訳ないのですが

C95は「日曜・東地区・タ46a『大福フューチャーラボ』」にてサークル参加いたします。

作品紹介……の前に、お詫び

そして、頒布物紹介の前にお詫びがございます。

このたび、C94頒布作品Bulletronica体験版内において重大なバグが存在し、
それの修正に時間をかけた結果、未だにバグが修正した内容がアップできておらず、制作側が想定していたゲームプレイができなくなっております。
有償頒布として体験版を出した身で、このような体たらくになってしまったこと、大変申し訳ございませんでした。


2018年6月頃から11月頃まで、職場での様々な要因が重なって精神的に追い詰められていた状況にあり、
満足なゲーム開発ができなくなってしまっておりました。
また、作曲に付きましても、とあるコンピにお誘いいただくまでほとんどまともに音を出せないぐらいに精神的なスランプとなっておりました。
今回のC95:2日目までには何とかしたいところなのですが、これも正直自身のメンタルとの戦いになりますので、
バグが修正しきれる確約はできません。
当日バグが修正しきれている場合のみ、Bulletronicaは頒布いたします。

新作

・作業用BGMCD「For Good Routine」 音楽CD:500円
 まさかの音楽CD、多分6曲ぐらいになるであろうミニアルバムです。
 詳細は特設サイトを後日作りますので、よろしくお願いいたします。

旧作

・GrooveHolic Type-R rev2 DLカード:1000円
音楽ゲームです。今回、更に軽くなったチューニング済みです。
このチューニング内容については、冬コミまでにブログ記事としてアップいたします。

・L.F.O. DLカード:500円
STGです。Switchでも出ました。

・L.F.O. -Audio Drug- DLカード:500円
↑のサントラです。

 ・Bulletronica体験版 DLカード:100円
前述の通り、アップデートが間に合ったら頒布されます。



以上、何卒宜しくお願いします。

【UE4】BlueprintだけでObjectPoolを作ってみた:追記あり・画像差し替えました

スクリーンショットの画質が、アップロード時に劣化していたため
設定を変更して画像の差し替えを行いました。クリックした画像が潰れてしまっていたら、クリックして飛んだ先にある「オリジナルサイズを表示」
をクリックしてみてください。

概要

Unreal Engine 4 (UE4) その2 Advent Calendar 2018 の15日目になります。

多くの場合、ゲームの中ではオブジェクトを作って消しての繰り返しが大量に発生しています。

アクションゲーム等をプレイしていても、エフェクトや敵弾、更には敵自身など、ゲーム中に大量に出現しては消えていくモノばかりです。
弾幕シューティングなど、ものすごい物量のオブジェクトを作っては消し、作っては消しするゲームではより顕著ですね。

この「オブジェクトの生成と削除」をnewとdeleteで行うと、そのたびにメモリを確保したり全体の初期化が走ったりで
コストがどえらいことになるので、ゲーム制作ではオブジェクトプーリングという手法で一度使ったオブジェクトを再利用するようにするケースが多いです。

今回、この仕組みをBlueprintだけで作ってみることにしました。


※この内容は、UE4.20.3で作ったものです。

オブジェクトプーリングとは

端的にいうと、「オブジェクトを前もって作ってプールしておいて、新しく作る代わりにそこから使って、消す代わりにそこへ戻す」というものです。
ゲームもしくはシーンの開始時にオブジェクトを大量に作る下準備をして、ゲーム実行中にそこからオブジェクトを使います。
これによって、オブジェクトを作るたびに新しくメモリを確保したり、消すたびにゴミを溜めたりすることを減らします。
UnityやUnrealでは、ある程度使用済みのメモリがたまるとGCが走るのですが、その際にカクつきが発生するので、
アクションゲームやシューティングゲームなど、ゲーム中にカクつきが走ると致命傷になりうるジャンルのゲームでは、
オブジェクトプーリングはとても有効であると言えます。


下準備

では、プールを作る前にプール用アクタの基底クラスから作りましょう。
先にプーリングしそうなオブジェクトのIDを列挙型で作っておきます。

次に、基底クラスとなるPoolActorBaseを作ります。

このクラスは継承されることが前提なので、イベントグラフを見てもすっからかんです。


変数には
・ActorID(さっきのIDが入る)
・IsActive(アクティブかどうか)
・ManagerRef(あとで作るマネージャへの参照)


関数には
・SetActive(アクティブにするときに呼ばれる)
・SetActiveEnd(アクティブにしたあと、初期化処理等が終わったタイミングで呼ばれる)
・SetDeactive(非アクティブにする際に呼ばれる)
・SelfKill(自滅おまとめセット。プールから自身を非アクティブにする一連の流れをまとめたもの)


をそれぞれ用意しました。


各関数の中身は以下のとおりです。

ObjectPoolManagerを作る

では、実際にオブジェクトプールを持っているObjectPoolManagerを作ります。
まずプール用の構造体ObjPoolStructを用意しておきます。

・ObjectID:前に作ったObjID Enum
・MaxNum:プールに作っておく数
・ActiveArray:アクティブ状態になっているアクタの参照配列
・NotActiveArray:非アクティブ状態になっているアクタの参照配列



ObjectPoolManagerの中身はこうなっています。

・Pool:上記ObjPoolStructの配列(初期値の設定が必要)
・ClassMap:どのIDとクラスを紐づけするMap(初期値の設定が必要)
・IDMap:IDと配列番号を紐づけするMap(空っぽにしておく)


Poolの設定内容の例を挙げておきます。


ClassMapの例はこちらです。


IDMapはプール初期化の際に自動的に作られます。
プールのイベントグラフはこのように作りました。

「IDに対応したクラスのアクタを設定されている数だけスポーンし、即非ActiveにしてNotActiveArrayへ突っ込み、最後にIDと配列番号を紐づけしてIDMapへ追加」
という処理を、Poolの数だけ繰り返します。


オブジェクトを生成する際と削除する際には、CreatePoolObj関数とKillPoolObj関数を呼びます。


CreatePoolObj関数



CoreSystemRef変数は今回の内容と関係ないので無視してください。
TempActorはこの関数内のローカル変数で、PoolActorBase型です。
【追記】一部、処理が重くなる箇所がありましたので変更いたしました。最後の追記欄をご覧ください。



KillPoolObj関数

作ってたゲームではKillPoolObjはSelfKill経由で呼び出される想定だったので、ここにはSetDeactiveが用意されていませんでしたが、
この辺の作りはゲームごとに適した感じでやればいいと思います。


継承の例

この基底クラスをもとに敵弾を作るとこうなります。

基底クラスの関数をオーバーライドして、処理を付け加えていきます。
また、弾が寿命を迎えて消えるときにDestroyActorではなくSelfKillを呼び出しているところにも注意してください。

敵がこの敵弾を撃つ際は、CreatePoolObjで生成するようにします。
3Way弾を作るときの例です(きたなくてすまん)


ObjectPoolを使った場合と使わなかった場合の比較

スペックがスペックなので、比較しづらいかもしれませんが、GCが入ったときのカクつきは決定的だったので
それだけでもわかりやすいかとは思います……



■スペック
Core i7-8086K 4.0GHz
・メモリ 64GB
・GeforceGTX1080Ti



■比較内容
毎フレームごとに3Way弾を発射する敵を左右5体ずつ用意し、片側ずつ弾を発射し続けてもらう。
3秒で弾は消滅する。
左側の敵はオブジェクトプールから弾を生成して、弾は消滅時にプールへ戻る。
右側の敵は直接弾をスポーンして、弾はDestroyActorで消滅する。
録画は2分間行う。



左側の敵の弾生成


右側の敵の弾生成


それでは、録画結果をご覧ください。

オブジェクトプールを使わなかった場合

youtu.be

オブジェクトプールを使った場合

youtu.be

録画結果からわかること

オブジェクトプールを使わず逐次スポーン・デストロイを繰り返していると、
約1分ごとにGCによるカクつきが発生しているのがわかります。
オブジェクトプール利用時には、これが発生せず、2分間安定した動作を続けているのがわかります。
また、録画後に5分ほど追加動作させましたが、それでもカクつきは起きませんでした。
実際のゲームでは、弾だけでなくエフェクトや敵自身など、サイズが重いオブジェクトも大量に出現、消滅するので
スポーンとデストロイを繰り返していては、GCによるカクつきは避けられないと思われます。
STGで1分ごとに突然カクつくとかゲームにならないですからね。


また、オブジェクトプール利用時のほうが平均して1~2FPSほど速いのがわかります。
PCのスペックがかなり高めなので差は分かりづらいかもしれませんが、
これがもっと低スペックなPCやAndroid等ならば差は大きくなるのではないかと思います。


まとめ

そういうわけで、Blueprintでもオブジェクトプールを作ることができました。
もっと洗練されたものを作られてる方もたくさんいらっしゃると思うので、
ぜひそういう方々の知見が公開されてくれるといいなと思います。

追記

UnrealのArrayでは、アイテムをRemoveしたときに、
それより先にある全アイテムを一つ前にコピーしてArrayを詰めています。
そのため、Create Pool Objの際に一番最初のオブジェクトから使うのではなく、一番後ろのオブジェクトから使うべきでした。
申し訳ございませんでした。


この記事はここまでです。お疲れ様でした。
明日はka-sさんの
【UE4】ボタンポチっでiOS/AndroidのDevelopment/Shippingの計4つのバイナリを作ってDeploygateに上げる【Jenkins】 - Qiitaです。

VOCALOIDで曲を書かなくなって

まず最初に、この記事は技術にまつわるものではありません。
ご了承ください。

VOCALOIDで曲を書かなくなった

ある日、なんとなく書く気がなくなってしまった。
今もなんとなく、書く気が起きない。


思い返せば、自分のボカロPとしての経歴はあまりにぐちゃぐちゃだったし、
大問題児だったし、
そんな中でも自分の曲を聴いて好きだと言ってくれる人が居たり、
CDを手にして喜んでくれる人が居たりしたのは幸せな人生だったんだと思う。


なんだかよくわからない。
ボカロ曲を聴く事はある。最近の新しいボカロPはオシャレな音使いをする人が多いなあと思うし、
未だにクラブ系のかっこいい音を作り続けてる人たちもいるし。
ただ、ボカロエディタを立ち上げて画面に向き合うと、妙に虚しい気持ちになる。

OBと批評家と

いつだったか、その昔私とぶつかりまくっていた(今思えば、私に胸を貸してくれていた)パッチワークPが、
マジカルミライに幻滅したという記事を上げ、ボーカロイドから目に見えて距離を置いたのを見たことがある。
あれほど静かな中に情熱を湛えていた人が、ボーカロイド評論の第一線から退いたことへの衝撃は大きかった。


以前一度寄稿させていただいた、中村屋与太郎さん率いる白色手帖もボカロ評論本の定期リリースを止めていた。
それほどまでに、ボーカロイドは議論の余地もなくなるほどに色数を減らしていたのだろうか。


いや、確かに減っていた。カラーパレットは減っていた。
65536色ぐらいは識別できていたはずのそれは、256色ぐらいになっていたのではないか。


マジカルミライ2013はパッチワークPにとって衝撃のライブであったようだが、
私にとっての衝撃はマジカルミライ2014,2015,そして2017である。


各ライブのセットリスト及びテーマソングは下記参照のこと。
マジカルミライとは (マジカルミライとは) [単語記事] - ニコニコ大百科


今だからこそ言えるが、マジカルミライに「未来」なんぞ全く感じられなかった。
「現在」様々な楽曲イラストその他諸々を生み出し続けている有象無象のクリエイターにすらそっぽを向いた、
「過去」だらけのお祭りだった。


毎年大体の曲は変わらない、2010年以前の曲ばかり、
挙句の果てにテーマソングは、
とっくに商業音楽に羽ばたいていったOBが、記念行事にだけ帰ってきて主役を張るような人選。
それがミライというのなら、まさにマジカルである。魔法でも使わなければそんな話は通らないだろう。


様々な企業のボーカロイド曲の扱いも変わり始めていた。
最新の曲に目を向ける割合が減っていった。


文化の広がりを歓迎しているはずの各企業は、
とある時代を境にして、現在を追うことをやめ始めたように見えた。

ボーカロイドは本当に自由な文化だったのか

その昔、バンドブームがあった頃、フォークブームがあった頃。
彼らの手にした楽器はどこ製だっただろうか。
日本のもの、海外のもの、はたまたレッドスペシャルみたいに自作したものもあっただろう。


ボーカロイド曲というのは、そういうわけにはいかなかった。


少なくともボーカロイドという枠組みの中で、VOCALOID2~3の時代で考えても20社行くか行かないか程度、
その中でもクリプトン、インターネット、1stPlace、AHSの四天王に大元締めのYAMAHAが強かった。
これらの企業の製品を持っていないとボーカロイド曲というのは生み出せなかったと考えると、
どこのギターを持っていたって参入できたブームや文化とは全くの別物だったと言えるだろう。


ボーカロイド文化というのは、近代の音楽文化の中で唯一、
「企業が完全に管理することが実際に可能だった文化」なのではないかと、最近思うことがある。
そしておそらく、実際にそれは起きたのだろう。
無限に広がる余地は十分にある文化。
しかし企業としてはこれまでその文化を自分たちの中で管理できていた。


つまり、管理しきれなくなる前に閉じなければいけない。


ボーカロイドを作った企業、動画サイトの運営、それにまつわるコンテンツを二次利用する企業。
それらの利害が一致したとき、
ボーカロイド文化は、企業主導で閉じられようとする方向へ動いたのではないだろうか。
終わらせるのではなく、閉じる……世代交代、新陳代謝の否定へと。

砂の惑星を作ったのは誰か

そこでマジカルミライ2017の「砂の惑星」である。
発表当時、私は「卒業したOBがなーに上から目線の曲書いて小遣い稼ぎしとるんじゃ最近のボカロの流れ全然見とらんじゃろ」とか激怒していたのだけれど、
今思えばあの曲はどこまでも正しかった。
彼の目から見ればその頃のニコニコはすでに砂の惑星であった、
いや、
彼はもう何も見なくても、それが砂の惑星であることを知っていたし、
そうでなくてもそうなるであろうことを知っていたのだろう。


砂漠は何も、最初から砂漠だったわけではない。
雨雲が去って干からびたのだ。
では雨雲は何故去ったのか。
これ以上の繁栄は、自分たちの管理できるキャパを超えるからではなかったか。


そして、彼は雨雲の上に住みながらその曲を「施した」のだと、私はそう思った。


突然変異で水がなくてもジャックの豆の木ぐらいに伸びる植物が出てくるかもしれない。
そうなったらそれはそれで収穫すればいい。それも雲の上に仲間入りさせてやればいい。
少なくとも、これ以上雨を降らせてやる必要はない。


そんな空気を、ひしひしと感じるのだ。

それでも曲を書きたい

と、ここまで書いたものの、
結局は現実逃避だったり、自分が曲を書かない言い訳の一部だったり、
そういうものの中にこの文章はあるわけだけど、


それでもボーカロイドで曲を書きたい自分がまだいるらしい。
見事な呪いだと思う。
去っていった雨雲は、恵みの雨の味を知った人々のその後なんて気にしないんだろう。
誰が最後の一人になるのやら。

現在制作中のVRガンシュー×音ゲーについて:進捗と悩みと

最近ツイッターにも動画を上げていましたが、UE4を使ってOculusGo向けのVRガンシュー×音ゲーなるものを制作しています。

が。
正直なところ、現在このゲームはこのままOculusGo向けに開発を続行するか否かを検討する段階にあります。
これまでの進捗と、その段階に至るまでの悩みとにつきまして、ここに記録しておきたいと思います。

音楽ゲームとしての形は出来て来ている

このゲームを作るにあたっての目標は2つありました。

UE4でOculusGo向けの遊べるアプリを一つ作って、VR向け開発を経験してみよう
音楽ゲームに共通で使えそうな部分をコアシステム化して、今後使い回せるようにしたりアセットストアに出品を挑戦したりしてみよう

この2つの目標において、進捗は順調です。
音楽ゲーム用のコアシステムはいい具合に出来上がってきており、実際にオブジェに対して入力と判定も取れるようになりました。
ここに音楽ゲームエディタとしても汎用的なものを作ることができれば、2つ目の目標は十分に実現できるでしょう。

しかし、実際にこのゲームをテストプレイしたときに没入感とか、面白さとかをどれぐらい感じられるかという話になると、
Oculus RiftやViveを使ったときのようなそれとは全く違うなと感じざるを得ません。


「ポジトラができない」が実はかなり重かった

Oculus Goを使う際、コントローラやヘッドセットの向きは取れても位置は取れません。
もちろん裏技的なテクニックを使って位置を擬似的に取得しようという方もいらっしゃいますが、
銃撃が必要なこのゲームでコントローラが使えなくなっては本末転倒です。
ポジショントラッキングができないのはOculusGo本体も同じなので、立っても座っても歩いても自分の位置は移動しないし、
腕を目の前へ構えて銃撃しても、画面の中のモーションコントローラActorは向かって右下あたりで動いてます。

これが生み出す違和感について、私は甘く見すぎていました。
こっちへ向かってくるオブジェに対応させようとすると自分の動きが多くなるからポジトラできないGoだと違和感が出るだろう→じゃあ向こうにある的を撃たせようぜ
と思って作ってみたら、手元が動かせないせいで大きな違和感が生まれてしまったのです。

そこで考えたのが「じゃあ銃のモデルを消そう。」ということで、
今はそちらの方向で対処しようとしてます。

やっぱり撃つなら両手だよ

二丁拳銃のほうがかっこいいし撃ってて気持ちいいに決まってるだろ!!
あと片手しか使えないと譜面難易度的にも限界があるよなと感じました。

RiftとかVive向けに作ると両手が使えるので、ターゲットプラットフォームをそっちに変えるならワンチャンあるかも、とは思っています。

やっぱりOculusGoでUE4は重い

スペック的な問題はどうしても出てきてしまいました。
綺麗なグラフィックは出せそう
でもUE4でガッツリC++書かないと重い
書いてても案外重かったりする
個人開発レベルで最適化しようとするのは厳しいなあ……

選択肢

というわけで現在、このゲームをどうするかで悩んでいるわけですが

  1. 現在のプラットフォームで最後まで作ろう
  2. OculusRift/Vive向けにPCVRコンテンツとして作り、Goにはライト版みたいな形で移植しよう
  3. ペンディング。現実は非情である

答えは……
という感じで色々悩んでいます。
というご報告でした。

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

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

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

第5回、ゲームとしての体をなすために

前回までで、


譜面データを読み込み、
画面に表示し、
それを流し、
入力に対して判定を取る


までは実装できました。
さてようやく、音楽ゲームらしく、音を鳴らすパート……にしたいところですが、
その前にやっておくことがあります。
ゲームとしての体をなすために、タイトル画面、セレクト画面、リザルト画面をとりあえず組みましょう。

まずはタイトルを作る

前回の記事までで、GameMainを含めて4つのレベルを用意するところまではやりましたね。
f:id:dfk_ohnuma:20171208020049p:plain
では、その中のタイトル画面を用意します。

dfkfuturelab.hatenablog.com
この記事で使っていたBPをそのまま持ってきます。
f:id:dfk_ohnuma:20171213020140p:plain

とりあえずタイトル用ウィジェットを作ります。
f:id:dfk_ohnuma:20171213020257p:plain
ひどくシンプルな画面ですが、絵心がないので仕方ないね(諦め)
これじゃ嫌だ!という場合は色々デザインを頑張ってみて下さい。
まあ今回の大事な部分はそこではないので……

f:id:dfk_ohnuma:20171213020449p:plain
タイトル画面のウィジェットの中身はこんな感じです。シンプルですね
次に、選曲画面を作ります。

案外難しい選曲画面

(※選曲画面の背景については割愛します。今回は選曲画面のUIメニューの実装についてがメインになります。)
選曲画面では、譜面データの数が増えれば増えるほど項目の数が増えるわけです。
しかし、そのタイトルやら何やらを全て手作業で入力しなければならないとしたら手間の増え方がハンパナイです。
なので、せめて手作業でやるのは譜面データの追加ぐらいにして、それ以降は勝手にゲーム側で読み込んで処理してもらおうと思うわけです。

SelectLevel用に作ったBPはこちらです。全てウィジェットBPになります。
f:id:dfk_ohnuma:20171213021131p:plain
このうち、最低限必要なのはSongSelectとListItemです。残り2つは演出用に自分の趣味で用意したものです。
実際、SelectLevelのレベルブループリントには
f:id:dfk_ohnuma:20171213021244p:plain
こうあるだけです。
SongSelectWidgetを作成したら、後はその中でいろいろやってくれるようにします。

SongSelectWidgetの中はこうなっています。
f:id:dfk_ohnuma:20171213022238p:plain
この左側にあるSongSelBoxの中に楽曲の情報を入れていきます。
このSongSelBoxはScrollBoxという種類のUMGパレットを使っています。
ScrollBoxについては、

UMGのscrollboxをマウスやタッチを使わずにゲームパッドのみでスクロールさせる方法 - UE4 AnswerHub
limesode.hatenablog.com
qiita.com
これらのサイトも参考にされると良いと思います。

このScrollBoxに突っ込む楽曲情報のWidget、それがListItemです。
f:id:dfk_ohnuma:20171213022624p:plain
中身はとても簡素です。曲名を表示するテキストと、レベルを表示するテキストと、背景のImage。
f:id:dfk_ohnuma:20171213022720p:plain
アニメーションは右へずらすのと、戻すのの2つです。

f:id:dfk_ohnuma:20171213022959p:plain
イベントグラフには外部からそれぞれの値を設定するためのイベントだけがあります。

f:id:dfk_ohnuma:20171213023036p:plain
f:id:dfk_ohnuma:20171213023050p:plain
背景と選択時のマスク画像の変更についての関数が1つずつ用意されています。

ListItemの中身はこれだけです。

選曲画面の最初の流れ

今回の選曲画面の最初の流れですが、


1:譜面データの配列から1つずつ取り出し
2:TITLEコマンドとLEVELコマンドを見つける
3:ListItemを作って、そこにTITLEとLEVELを登録して、SongSelBoxの子供として登録する
4:全部終わったらカーソルを0番目にする
(4+:開始演出を入れる)
5:カーソルが合っている番号の楽曲情報をインフォ欄に書き込む


という形になっています。
これをBPで実装してみます。

f:id:dfk_ohnuma:20171213023921p:plain


ちょっと拡大してみます。
f:id:dfk_ohnuma:20171213024023p:plain

f:id:dfk_ohnuma:20171213024040p:plain


ここの開始演出については、選曲画面の実装に必須のものではないので割愛します。
また別の機会に書かせていただきます。
f:id:dfk_ohnuma:20171213024158p:plain
この「曲の情報をインフォ欄に登録」という部分については、
他にも使う箇所があったのでマクロにしました。
f:id:dfk_ohnuma:20171213024241p:plain


このマクロの中身については、こうなっています。
f:id:dfk_ohnuma:20171213024338p:plain


楽曲選択時のカーソル入力対応は以下の通りになります。
f:id:dfk_ohnuma:20171213024657p:plain
今までカーソルが合っていたListItemに非選択処理をしてやってから、選択先のListItemに選択時処理をするのを忘れないようにします。


拡大するとこんな感じです。
f:id:dfk_ohnuma:20171213024817p:plain


選曲決定時には、GameMainで譜面データを取得できるよう、選択された譜面データをGameInstanceに投げておきましょう。
f:id:dfk_ohnuma:20171213050310p:plain

最小限の構成で良ければ、囲んだ部分はいらないはずです。
囲まれている部分は演出用に組まれています。
f:id:dfk_ohnuma:20171213050600p:plain


これで、譜面データの配列にデフォルトの要素を設定してやることで
www.youtube.com
このように選曲画面のUIが実装できました。

なんとまあひどいリザルト

リザルト画面については、各判定がそれぞれGameInstance内に保存されていますので、
f:id:dfk_ohnuma:20171213051306p:plain
こんな感じにテキストをバインドしてやれば
f:id:dfk_ohnuma:20171213051356p:plain
リザルトに必要な要素を用意することが出来ます。

これでタイトルからリザルトまでの流れが実装できたので、今回はここまでです。

最後に

これでタイトル画面や選曲画面やリザルト画面をとりあえず作って、ゲームとしての形が整ってきました。
次回はいよいよ音の部分の実装です。

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

【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日まで全部私です)。よろしくお願いします。