現在制作中のVRガンシュー×音ゲーについて:進捗と悩みと
最近ツイッターにも動画を上げていましたが、UE4を使ってOculusGo向けのVRガンシュー×音ゲーなるものを制作しています。
【制作進捗】OculusGo用のガンシュー×音ゲー、オブジェと判定と、入力時のエフェクトまでつけました。だいぶ音ゲーっぽくなってきたな…… OculusGo実機で録画しています。 #UE4 #UE4Study #OculusGo #OculusGoDev pic.twitter.com/k3M6hPzzaj
— D.Ohnuma (@dfk_ohnuma) June 24, 2018
が。
正直なところ、現在このゲームはこのままOculusGo向けに開発を続行するか否かを検討する段階にあります。
これまでの進捗と、その段階に至るまでの悩みとにつきまして、ここに記録しておきたいと思います。
音楽ゲームとしての形は出来て来ている
このゲームを作るにあたっての目標は2つありました。
・UE4でOculusGo向けの遊べるアプリを一つ作って、VR向け開発を経験してみよう
・音楽ゲームに共通で使えそうな部分をコアシステム化して、今後使い回せるようにしたりアセットストアに出品を挑戦したりしてみよう
この2つの目標において、進捗は順調です。
音楽ゲーム用のコアシステムはいい具合に出来上がってきており、実際にオブジェに対して入力と判定も取れるようになりました。
ここに音楽ゲームエディタとしても汎用的なものを作ることができれば、2つ目の目標は十分に実現できるでしょう。
しかし、実際にこのゲームをテストプレイしたときに没入感とか、面白さとかをどれぐらい感じられるかという話になると、
Oculus RiftやViveを使ったときのようなそれとは全く違うなと感じざるを得ません。
「ポジトラができない」が実はかなり重かった
Oculus Goを使う際、コントローラやヘッドセットの向きは取れても位置は取れません。
もちろん裏技的なテクニックを使って位置を擬似的に取得しようという方もいらっしゃいますが、
銃撃が必要なこのゲームでコントローラが使えなくなっては本末転倒です。
ポジショントラッキングができないのはOculusGo本体も同じなので、立っても座っても歩いても自分の位置は移動しないし、
腕を目の前へ構えて銃撃しても、画面の中のモーションコントローラActorは向かって右下あたりで動いてます。
これが生み出す違和感について、私は甘く見すぎていました。
こっちへ向かってくるオブジェに対応させようとすると自分の動きが多くなるからポジトラできないGoだと違和感が出るだろう→じゃあ向こうにある的を撃たせようぜ
と思って作ってみたら、手元が動かせないせいで大きな違和感が生まれてしまったのです。
そこで考えたのが「じゃあ銃のモデルを消そう。」ということで、
今はそちらの方向で対処しようとしてます。
やっぱり撃つなら両手だよ
二丁拳銃のほうがかっこいいし撃ってて気持ちいいに決まってるだろ!!
あと片手しか使えないと譜面難易度的にも限界があるよなと感じました。
RiftとかVive向けに作ると両手が使えるので、ターゲットプラットフォームをそっちに変えるならワンチャンあるかも、とは思っています。
やっぱりOculusGoでUE4は重い
スペック的な問題はどうしても出てきてしまいました。
綺麗なグラフィックは出せそう
でもUE4でガッツリC++書かないと重い
書いてても案外重かったりする
個人開発レベルで最適化しようとするのは厳しいなあ……
選択肢
というわけで現在、このゲームをどうするかで悩んでいるわけですが
- 現在のプラットフォームで最後まで作ろう
- OculusRift/Vive向けにPCVRコンテンツとして作り、Goにはライト版みたいな形で移植しよう
- ペンディング。現実は非情である
答えは……
という感じで色々悩んでいます。
というご報告でした。
【UE4】UE4でシンプルな音ゲーを作ろう:その5
この記事は、「ひとりUE4 Advent Calendar 2017」の12/7担当記事です。
qiita.com
(あくまでも音ゲーとしての実装は自己流のものですので、
実際はもっと効率のいい組み方があったりすることもあると思いますが、
そういう場合は是非ブログ等でその技術をシェアしていただけるととても助かりますので
何卒よろしくお願いします……)
第5回、ゲームとしての体をなすために
前回までで、
譜面データを読み込み、
画面に表示し、
それを流し、
入力に対して判定を取る
までは実装できました。
さてようやく、音楽ゲームらしく、音を鳴らすパート……にしたいところですが、
その前にやっておくことがあります。
ゲームとしての体をなすために、タイトル画面、セレクト画面、リザルト画面をとりあえず組みましょう。
まずはタイトルを作る
前回の記事までで、GameMainを含めて4つのレベルを用意するところまではやりましたね。
では、その中のタイトル画面を用意します。
dfkfuturelab.hatenablog.com
この記事で使っていたBPをそのまま持ってきます。
とりあえずタイトル用ウィジェットを作ります。
ひどくシンプルな画面ですが、絵心がないので仕方ないね(諦め)
これじゃ嫌だ!という場合は色々デザインを頑張ってみて下さい。
まあ今回の大事な部分はそこではないので……
タイトル画面のウィジェットの中身はこんな感じです。シンプルですね
次に、選曲画面を作ります。
案外難しい選曲画面
(※選曲画面の背景については割愛します。今回は選曲画面のUIメニューの実装についてがメインになります。)
選曲画面では、譜面データの数が増えれば増えるほど項目の数が増えるわけです。
しかし、そのタイトルやら何やらを全て手作業で入力しなければならないとしたら手間の増え方がハンパナイです。
なので、せめて手作業でやるのは譜面データの追加ぐらいにして、それ以降は勝手にゲーム側で読み込んで処理してもらおうと思うわけです。
SelectLevel用に作ったBPはこちらです。全てウィジェットBPになります。
このうち、最低限必要なのはSongSelectとListItemです。残り2つは演出用に自分の趣味で用意したものです。
実際、SelectLevelのレベルブループリントには
こうあるだけです。
SongSelectWidgetを作成したら、後はその中でいろいろやってくれるようにします。
SongSelectWidgetの中はこうなっています。
この左側にあるSongSelBoxの中に楽曲の情報を入れていきます。
このSongSelBoxはScrollBoxという種類のUMGパレットを使っています。
ScrollBoxについては、
UMGのscrollboxをマウスやタッチを使わずにゲームパッドのみでスクロールさせる方法 - UE4 AnswerHub
limesode.hatenablog.com
qiita.com
これらのサイトも参考にされると良いと思います。
このScrollBoxに突っ込む楽曲情報のWidget、それがListItemです。
中身はとても簡素です。曲名を表示するテキストと、レベルを表示するテキストと、背景のImage。
アニメーションは右へずらすのと、戻すのの2つです。
イベントグラフには外部からそれぞれの値を設定するためのイベントだけがあります。
背景と選択時のマスク画像の変更についての関数が1つずつ用意されています。
ListItemの中身はこれだけです。
選曲画面の最初の流れ
今回の選曲画面の最初の流れですが、
1:譜面データの配列から1つずつ取り出し
2:TITLEコマンドとLEVELコマンドを見つける
3:ListItemを作って、そこにTITLEとLEVELを登録して、SongSelBoxの子供として登録する
4:全部終わったらカーソルを0番目にする
(4+:開始演出を入れる)
5:カーソルが合っている番号の楽曲情報をインフォ欄に書き込む
という形になっています。
これをBPで実装してみます。
ちょっと拡大してみます。
ここの開始演出については、選曲画面の実装に必須のものではないので割愛します。
また別の機会に書かせていただきます。
この「曲の情報をインフォ欄に登録」という部分については、
他にも使う箇所があったのでマクロにしました。
このマクロの中身については、こうなっています。
楽曲選択時のカーソル入力対応は以下の通りになります。
今までカーソルが合っていたListItemに非選択処理をしてやってから、選択先のListItemに選択時処理をするのを忘れないようにします。
拡大するとこんな感じです。
選曲決定時には、GameMainで譜面データを取得できるよう、選択された譜面データをGameInstanceに投げておきましょう。
最小限の構成で良ければ、囲んだ部分はいらないはずです。
囲まれている部分は演出用に組まれています。
これで、譜面データの配列にデフォルトの要素を設定してやることで
www.youtube.com
このように選曲画面のUIが実装できました。
なんとまあひどいリザルト
リザルト画面については、各判定がそれぞれGameInstance内に保存されていますので、
こんな感じにテキストをバインドしてやれば
リザルトに必要な要素を用意することが出来ます。
これでタイトルからリザルトまでの流れが実装できたので、今回はここまでです。
最後に
これでタイトル画面や選曲画面やリザルト画面をとりあえず作って、ゲームとしての形が整ってきました。
次回はいよいよ音の部分の実装です。
以上で今回の記事は終わりです。お疲れ様でした。
アドカレの翌日の記事も私です(というか25日まで全部私です)。よろしくお願いします。
【UE4】UE4でシンプルな音ゲーを作ろう:その4
この記事は、「ひとりUE4 Advent Calendar 2017」の12/6担当記事です。
qiita.com
(あくまでも音ゲーとしての実装は自己流のものですので、
実際はもっと効率のいい組み方があったりすることもあると思いますが、
そういう場合は是非ブログ等でその技術をシェアしていただけるととても助かりますので
何卒よろしくお願いします……)
*第4回、いよいよ譜面を叩く時。
というわけで前回の続きです。
前回の記事では、譜面が流れてくるところまでが実現できました。
今回は、それに入力に対応し、判定を取れるようにしましょう。
叩く基準、それが判定ライン
まずは判定ラインを作ります。これはあくまでも見せかけのためのものですから、
適当なキューブを伸ばしてライン上にすれば良いかと。
これで判定ラインが出来ました。
あっさりすぎるだろ。
あと、全てのシーケンスラインBPのX座標を、判定ラインの線に合わせて下さい。その位置を基準にして譜面は配置されていきますので、
ここに合わせていないとジャストのタイミングで判定ラインと重ならなくなります。
情報を登録していくスタイル
というわけで、次に判定用の処理を考えましょう。
シーケンスラインに並べられたオブジェは、原則として一番手前側にあるものから処理されていきます。
配列で言えばその時の0番目ですね。
入力があった際、比べる先は配列の0番目、そして内容は、
「入力があった時点の楽曲開始からの経過時間」と「該当オブジェに登録された時間」を比較すれば良いわけです。
それではAddNoteイベントを拡張してみましょう。
譜面を配置すると同時に、NoteArrayという配列型変数へ、
オブジェへのリファレンス、オブジェの登録時間、オブジェのタイプをそれぞれ突っ込みます。
オブジェのタイプについては、今はまだロングノートの事を考えないようにするために、一切気にしないでおいてください。
これで、譜面が配置されると同時に譜面が配列へ突っ込まれるようになりました。
このNoteArrayはNoteInfoStructという構造体変数を配列にしたものです
これで、シーケンスラインごとにオブジェを配列にして管理することが出来るようになりました。
また、楽曲の開始前にすこしオフセットを取りたい場合(ゲームメイン画面に入って2秒ぐらいしてから開始したい、とかそういう場合)
こうやって、配置場所にオフセットを足してやって下さい。
登録した情報は使ってなんぼ
というわけで、入力された際にNoteArrayの一番上のオブジェの情報を参照することで、
入力に対して判定を取ることが出来ますね。
それでは早速、そのためのマクロを作ります。
現在の時間と、NoteArrayの一番上の要素の時間とを比較し、差し引きした値を判定に使うために返します。
これの絶対値が小さいほど、正確なタイミングで入力されたということになります。
ここで戻り値を絶対値にしないのは、見逃しMISSを判定できるようにするためです。
これを使って、さっそく入力用の処理を作りましょう。
判定用の変数はPerfect、Great、Good、Bad、Missと5種類ありましたが、
Great判定を採用するのを辞めたのでこうなってます。
判定の数や基準とする判定タイム幅については自由に決めてみて下さい。
見逃したらダメ、ゼッタイ。
更に見逃しMISSを実装しましょう。
シーケンスラインのTickの最後尾に、見逃しミス用の判定を付け足します。
先程のマクロを絶対値ではなく、見逃したときだけ判定が成立するように使っているのがわかりますね。
起承転結
さてこれで判定は対応できましたが、ここで大事なものを付け足さないといけません。
それは「終わり」です。
曲がいつ終わるのかを情報としてゲーム側へ渡せないと、
いつまでもゲームが続いてしまいます。
なので、まずは譜面に終了用のコマンド「END」を追加しましょう。
コマンドEND:引数1…到達したら終了する小節数
そして、このコマンドをSequenceloaderが読めるようにしてあげます。
そこから伸びるピンはここへつなぎます。
あとは終了時間を超えていないかチェックすることで、
自動的に楽曲終了→リザルトへの移行が出来るようになります。
レベルはこうやってタイトル・セレクト・ゲームメイン・リザルトの4つを作っておけば、
簡潔なゲームであれば最低限のゲームとしての遷移は出来ると思います。
ついでにちゃんと動いているかどうか確認するためにウィジェットも作りましょう。
こうやってテキストブロックを用意して、まず最初にGameInstanceのリファレンスを用意して
それから、それぞれのテキストブロックの内容について関数をバインドさせてやればよいでしょう。
とりあえず、ここまでの状態で譜面を流してみて、
入力をちゃんと取れるかを確認してみましょう。
t.coというわけで入力と判定が取れるようになったので、試しにプレイしてみました。入力の判定と、見逃しミスがしっかり動作しているのがわかると思います。次はノートが爆発するときのエフェクトを付けましょう。 #UE4 #UE4Study #indiedev #土日で音ゲー作ろう pic.twitter.com/3uqoifRRak
— D.Ohnuma@冬コミ準備中 (@dfk_ohnuma) July 29, 2017
まだ爆発などは用意してませんが、タイミングよく入力すればオブジェが消えてくれるはずです。
次回はゲームとしてタイトルからリザルトまでを回せるように整えていきます。
最後に
これで入力に対して判定を取ることが出来るようになりました。
この時点ですでに、音ゲーとしての遊び方を用意することは出来ました。音は鳴ってないけど。
次回はタイトル画面や選曲画面やリザルト画面をとりあえず作って、ゲームとしての体裁を整えていきます。
以上で今回の記事は終わりです。お疲れ様でした。
アドカレの翌日の記事も私です(というか25日まで全部私です)。よろしくお願いします。
【UE4】UE4でシンプルな音ゲーを作ろう:その3
この記事は、「ひとりUE4 Advent Calendar 2017」の12/5担当記事です。
qiita.com
(あくまでも音ゲーとしての実装は自己流のものですので、
実際はもっと効率のいい組み方があったりすることもあると思いますが、
そういう場合は是非ブログ等でその技術をシェアしていただけるととても助かりますので
何卒よろしくお願いします……)
*第3回、いよいよ譜面が動く時。
というわけで前回の続きです。
※前回の記事に訂正点がありましたので、まだ確認してない方は前回の記事を再度確認して下さい。
シーケンスラインが出来た、
譜面も配置できた、
となれば次は、譜面を流してみるところからですね。
譜面が流れるようにする、と言っても、前回の記事を見れば分かる通り、
今回は「シーケンスラインActorそのものが移動することで、その子供になっているオブジェも揃って移動する」という仕組みにしています。
ですので、やるべきことは「シーケンスラインを動かす」ということですね。
現在、シーケンスラインはこのような構成になっていました。
ということはScene1を動かせば、その下にあるNoteたちは全て動いてくれます。
曲が始まったかどうかを判断するIsPlayingというbool型変数を用意して、組んでみるとこうなります。
BaseVelocityは前回も出てきた基本秒速です。
これにDeltaSecondsと-1をかけているので、Scene1とそこにひっついたオブジェたちは秒間(-基本秒速)だけX方向に移動します。
もちろん、プレイ中かどうかを示すフラグが出来た以上は、
曲開始時の処理もお忘れなく。
これで、何らかのボタンで6レーン分のStartSongを呼び出してやることで、
t.co譜面が流れるようになりました~~L( ^ω^ )┘♪└( ^ω^ )」♪ いい感じに譜面が流れてて嬉しいですな まだまだ譜面をみやすくしたりする必要がありますが、次はいよいよ入力の受付ですね~ #UE4 #UE4Study #indiedev #土日で音ゲー作ろう pic.twitter.com/KzqCY1x05r
— D.Ohnuma@冬コミ準備中 (@dfk_ohnuma) July 29, 2017
このように、奥から手前まで譜面が流れてくるようになりました。
それでは次に、プレイヤーが入力する部分を作ります。
入力はキーバインドで
まずはインプット用のBPを作ります。
これを使って……
まず全てのシーケンスラインを取得して、配列SeqLineへ入れます。
6つのシーケンスラインにそれぞれ「Line1~Line6」みたいな感じでタグを付けておいて、それを引っ張ってきています。
そうすることで順番通りに配列に突っ込めるはずです。
次に入力ですが、今回は直接キー入力イベントを作るのではなく、
「キーバインド」を使ってみましょう。
キーバインドは、「Aキー」とか「ゲームパッドAボタン」とかのキー入力イベントの代わりに、
「攻撃ボタン」などの自由な名前で入力イベントを作り、それに対応するキーを登録することで、
「AキーかゲームパッドAボタンで攻撃」という場合に「攻撃ボタン」イベントだけで処理を作ることが出来たりする便利な機能です。
こうして書いていてもよくわからないと思うので、コチラをご覧ください。
「プロジェクト設定→インプット」で出てきます。
ここの「アクションマッピング」を開いて
このように好きな名前のインプットイベントと、
それに対応させるキーの登録を行います。
こうすることで、ブループリントの中で
先程登録したキーバインド用のインプットイベントを生成することが出来るようになります。
これを使うことで、キーボードでもゲームパッドでも同じイベントを呼べるようになりますし、
何かの事情があって攻撃ボタンなどに割り振るボタンが変更されたとしても、
BP上では攻撃ボタンのイベントはそのままにしておけるのです。
というわけでそれぞれのラインへ入力通知を送る用に組みました。
ここにある「PushKey」「ReleaseKey」イベントは、
シーケンスラインのアクタの中に作ったカスタムイベントです。
ここから判定のシステムを作っていくわけですが、
今日の部は一旦ここでおしまいです。
【UE4】UE4でシンプルな音ゲーを作ろう:その2
この記事は、「ひとりUE4 Advent Calendar 2017」の12/4担当記事です。
qiita.com
(あくまでも音ゲーとしての実装は自己流のものですので、
実際はもっと効率のいい組み方があったりすることもあると思いますが、
そういう場合は是非ブログ等でその技術をシェアしていただけるととても助かりますので
何卒よろしくお願いします……)
第2回、それは譜面を解読する回。
というわけで前回の続きです。
前回は譜面用のデータテーブルを解読するためのBPを作る途中で終わりましたね。
こんな感じで。
それではこのMakeNote関数は今どうなっているかといいますと、
まだ空っぽです。
だって、Note(オブジェ)をMake(作る)といっても、
どこに作るねん!!!って状況じゃないですか!
というわけで、このMakeNote関数を使って譜面を設置するための、
譜面レーンを用意しましょう。
実際のゲーム画面をやっと作り始めることになります。
シンプルでいいので、メイン画面を作る
だいたいPlateを引き伸ばす感じでいいので、作ってみます。
こんな感じに左右に1枚ずつ板を用意して
マテリアルをいじって(自作マテリアルです、普通はテクスチャ書くなり、キューブを引き伸ばして棒を作るなりなんなりしてレーンの仕切りを作ればいいと思います)
このように3ラインに見えるようにして
というあっさりした作業の結果がこれです。
これについて凄く雑な書き方をしているのは、
板置いて仕切り置くだけでいいからです。
特にこの部分に技術的なTipsになりうるものはないので、皆さんも各々のやりやすい形で作ればいいと思います。
今回の主役ことオブジェを作る
そしてオブジェ用のBPを作るわけですが、
今回はActorを作るのではなく、ActorComponentを作ります。
この理由は後々説明します。
※おわび
当初ここで作るオブジェBPはアクタコンポーネントであると書いておりましたが、
一度上手く行かなかった時の作り方でした。
土日で制作したときも、結局はオブジェBPもアクタで作っておりましたので、
訂正しお詫び申し上げます。
正しくはこのようなアクタBPを作りました。
こうして新しくオブジェ用アクタが作られます。
このアクタはオブジェとして表示されるものを想定しているので、
こんな光る直方体を用意してみました。
特にこのBPにはイベントなどを持たせることもなく、編集はここで一旦終わります。
譜面をどうやって動かすか?
さてこれで譜面オブジェができました。
これを画面内に置いて移動させるわけですが、
実際にどうやって移動させるべきでしょうか。
一つ一つのオブジェに、移動量を設定して毎フレーム移動させる、それも良いかもしれませんが、
そうなるとオブジェの数だけTickなりなんなりが回ることになります。
それはそれでなんだか重いですし、
そもそもシーケンスラインに置かれたオブジェたちは全てが同じ速度で動くわけです。
つまり、同一ライン上のオブジェは全て、同じ動きをするわけです。
……ということは、
ライン用Actorの子供Actorとしてオブジェを設置して、
ライン用Actorを移動させるようにすれば、
子供であるオブジェたちも一斉に移動することになります。
イメージとしては、縄の上にオブジェを貼り付けて縄を引っ張ったら、貼られてるオブジェも一緒に引っ張られているような感じだと思ってもらえると嬉しいです。
レーン用のアクタを作ろう
というわけでシーケンスラインのアクタを作りましょう。
そして、Noteという名前のシーンコンポーネントを作ります。
そうしたら、このアクタの中に譜面配置用のイベントを作ります。
・イベントAddNote
NoteTime:そのノートが配置されるであろう時間(譜面データから読み取ったもの・それについての処理は後述します)
Type:ロングノートとか使いたい人用の拡張用引数 今は使わない
そして、この中の実装です。コメントを見れば何をしてるかはわかると思います。
この「基本秒速」というのは、オブジェが秒間どれぐらいの速度で動くようにしたいかの数値ですので、任意で決めて下さい。
まずこれで1つのラインが出来上がったので、ライン用Actorをレベル内に配置して、譜面ロード用のBPの変数にラインへのリファレンス変数SeqLineを作って登録してみましょう。
(仮処理だけどね)
複数のラインを用意するのであれば、SeqLineは配列にする必要が出てきます。
ラインの順番が正しく配列に組み込まれるよう、タグをつけるなりなんなりして工夫する必要があるので、気をつけて下さい。
ちなみにこの「LoadSequence」というイベントは前回から作っていた「譜面のデータテーブルを読み込むイベント」のことです
(前回イベント名とか書くの忘れてました、ごめんなさい)
それでは、いよいよライン上への譜面配置を行います。
譜面が設置される時間を計算するには?
譜面が設置されるための時間を計算するには、「その小節の頭までの時間」と、「小節の頭からどれぐらいの時間ずれるのか」が分かればいいですよね。
「その小節の頭までの時間」は、「1小節にかかる時間」×「小節数」で求められます。
「小節数」は譜面設置用コマンドと同値ですので、既に求めることが可能になっています。
となると、あとは「1小節にかかる時間」を求めることが必要ですね。
そこにはテンポが必ず必要になります。
1小節の時間を求めるために、このような処理を用意します。
そして譜面ロード用BPに1小節にかかる時間を入れておく変数、MeasureTimeを作り、
テンポを設定する際についでに計算するようにします。
これでMakeNote関数を働かせるための準備は揃いました。
いざ、オブジェ配置へ。
譜面配置コマンドの引数の仕組みについては前回も説明しましたが、
文字数がそのまま1小節の分割数になります。
譜面が配置される時間は、
譜面が配置される時間=該当小節の頭までの所要時間(A)+小節内の時間オフセット(B)
でしたね?
A=1小節あたりの所要時間(MeasureTime)×現在の小節数(譜面配置コマンド)
B=1小節あたりの所要時間(MeasureTime)÷小節の分割数(引数2の文字数)×現在の文字が何番目か(引数2の何文字目か)
というわけで、譜面が配置される時間はここまで用意した変数たちによって求めることが可能となりました。
実装前に、
ライン数を6つに増やしておきました。SeqLineへの登録の部分を書き換えて、変数も配列にしておく必要があります。
これで、譜面を配置する関数が実装できました。
*実際に見てみよう
先程も言いましたがBaseVelocityをいじって基本秒速を決めておきます。
これがオブジェごとの間隔をきめることにもなります。
譜面はこんなのでしたね?
譜面設置コマンド「1」の引数1が「0」を指してるので、
1小節目(曲自体は0小節目から始まります)の0レーン目にオブジェが設置されます。
BeginPlayかなにかで譜面ロード→設置を行われるように適当に組んで、
テストしてみましょう。
やったぜ。
更に譜面をちょっと書き換えてみましょう。
これで複数のラインに譜面が置かれるようになるのがわかるでしょうか?
そしてテスト。
勝ったッ!第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ファイルによっては開始地点からどれだけずらすかなども記録しておく必要があります。
というわけでこのような構造体を作りました。
3つの文字列変数。「コマンド」「引数1」「引数2」です。
コマンドによってその行の役割を設定し、引数1と引数2はコマンドごとの内容になります。
この構造体を元にして、譜面のデータテーブルを作ります。
今回の譜面データには、以下のようなコマンドが使えるようにしたいと思います。
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を作ります。
譜面を読み込む仕組みを作ろう
というわけで、
まあまず、こんな感じにしました。
譜面データの全部の行をチェックし、その列を分解して、最初のコマンド部分に入っている文字列でスイッチします。
この時、曲の名前やアーティスト名、ジャンル名、テンポ数値を何処かに表示させたいこともあるかもしれないので、
それらの値を保存しておこうと思います。GameInstanceを使いましょう。
なんとまあ乱暴な変数名だ
そしてこのGameInstanceをゲームに設定しましょう。
こんな感じで設定。
そしてその中に変数を用意しておきます。
上から、
曲名、アーティスト名、ジャンル名、テンポ、パーフェクト数、グレート数、グッド数、バッド数、ミス数、最大コンボ、そして得点です。
で、そこに色々保存していきます。
こんな感じ。ジャンル名、曲名、アーティスト名、テンポは保存できるようになりましたね。
更に、
「Make Note」なる関数を作りました。
中身は……おっと今日はここまで!!
今回は序章なのでここまでです
ということで結構スピーディに譜面を読み込む仕組みを作ってましたが、
ちょっとあっという間過ぎたでしょうか?もし速すぎてもうちょっと細かく説明を……ということがあれば、
私のツイッター等へご連絡下さいませ。
というわけで、今日の記事はここまでです。お疲れ様でした。
明日は第二回、譜面配置のシステムづくりです。
【UE4】BPをキレイにしよう:折りたたみ編
この記事は、「ひとりUE4Advent Calendar 2017」の1日目の記事です。
qiita.com
前回はコメント編として、
dfkfuturelab.hatenablog.com
このような記事を書きましたが、今回は折りたたみ編です。
折りたたみってなんだ
ブループリントで処理を書いていくと、どんどんイベントグラフの使用面積が大きくなっていきます。
これはこれで確かにめんどくさいのです。
前回のラストに貼ったこのスクリーンショットも、見やすくなったものの、一つ一つの処理を見ていこうとするとやはり大きいと言わざるをえないでしょう。
折りたたみには種類がある
試しに折りたたみたいノードを範囲で囲って、右クリックしてみると、こんなのが出てきました。
この赤く囲んだところが折りたたみ処理です。
「ノードを折りたたむ」
「関数に折りたたむ」
「マクロに折りたたむ」
この3つの処理から、その場その場にあったものを選ぶ形になります。
関数とマクロの違いはコチラで紹介する3つのブログ
UE4 関数とマクロの違いについて 凛(kagring)のUE4とUnityとQt勉強中ブログ
katze.hatenablog.jp
unrealengine.hatenablog.com
をぜひご一読ください。
ノードを折りたたむ場合
「ノードを折りたたむ」で折りたたむ場合、
このように新しいイベントグラフが生成され、そこに畳まれます。
しかし、これはイベントグラフであり、関数でもマクロでもないため
「複数個置くことができない(コピペしようとすると更に新しいイベントグラフが作られる)」
というところに注意してください。
そのため、「一つのイベントをまるまるくくってわかりやすくする」などの方法が良いかもしれません。
なので、今回は長かったイベント4つを折りたたんでみましょう。
こうなりました。この時点で、ブループリントを開いたときの見やすさはピカイチです。
関数に折りたたむ場合
(今回のBPでは関数にする予定の部分がないので、たたみません)
関数に折りたたむ場合は、先ほどとは違って新しい関数ノードが生成され、そこに畳まれます。
関数の一番の特徴は、関数内でローカル変数を持てるということです。
イベントグラフとは違い、作った関数はいくつもコピペして使うことが出来ます。
なので、何度も使いそうな部分は関数やマクロにすると良いかもしれません。
関数の中では、TimelineノードやLatentノードなど、一部のノードが使えないという制限がありますが、
代わりにPureフラグを立てることで実行ピンの接続を不要にできます。
これは使い所を間違えると処理がすごいことになるので、ヒストリアさんのこちらのブログを参考にして、
使い所を見極めると良いと思います。
historia.co.jp
マクロに折りたたむ場合
マクロに折りたたむ場合も、関数と同様新しいマクロノードが生成され、そこに畳まれます。
これもいくつもコピペして使えます(というかそのための……というか……)
インライン化機能もついており、実行時にはノードが展開されるので、結局マクロの中身全部をいくつもコピペするような形になります。
そのため、関数とは違って内部で値を保存したり…というのには不向きです。
しかし関数とは違って複数の出力ピンを持てたり、ノードの制限がなかったりとメリットも多いです。
マクロを使う際は関数のように呼び出しを行うのではなく、実行時にマクロの中身がマクロの置かれた場所へ置き換えられて実行されるので、
速度的なコスト面でも良いことがあるそうです。
unrealengine.hatenablog.com
そのあたりのことはalweiさんのブログで書かれてますよー。
というわけで幾つかのものをマクロにしてみました。
「こういう処理するためのマクロです」というコメントがついていれば、何かその処理で問題が起きた時に、
すぐに確認することが出来ます。
こうして……
処理ごとにイベントグラフへ折りたたみ、マクロにできそうなところをたたんで、それぞれの処理にコメントを付けたのがこれです。
最初は全部のイベントがごった煮になってましたよね、覚えてますか?
↑元々はこれでしたね(自分の傷をえぐりまくるスタイル)