【UE4】ウィジェットでメニュー画面などを作った際にマウス入力とキーボード/ジョイパッド入力を両立させる
ウィジェットブループリントあるある
UE4のウィジェットブループリント、とても便利に使ってます。
拙作「L.F.O.」のタイトル画面もポーズ画面も死んだときの画面もスコア表示等のUIも全部ウィジェットです。
しかしひとつだけ困ったことがありました……
「キーボード入力やジョイパッド入力のイベントがないやん!!!!」
そう、キーボードやジョイパッドでのインプットイベントに対応していなかったのです。
なので作ってみました。
間接的にインプットを取る
ウィジェットブループリントではキーインプットをイベントとしてグラフに作ることは出来ません。
しかし、アクタブループリントのキーインプットイベントからウィジェットブループリント内のイベントや関数を呼び出すことは出来ます。
例えるとこんな感じになります。
その手順を説明していきます。
インターフェースを作ろう
この方法で入力を取れるようにする場合、ウィジェット側に持たせておくブループリントインターフェースがあると便利になります。
というのも、ブループリントインターフェースは対象のオブジェクトを指定して呼び出す時、
そのオブジェクトのクラス名や実際にそのオブジェクトクラス内に該当するイベント及び関数が存在するかどうかに関係なく、
メッセージとして投げっぱなしジャーマンをしてくれるからです。
というわけで、さっそくブループリントインターフェースを作ってみましょう。今回は、
・カーソルを上移動させるCurUp
・同じく下移動させるCurDown
・決定ボタンを押すPushDecide
この3つのイベントをブループリントインターフェースで定義します。
あっという間に出来ました。
このブループリントインターフェースを、ウィジェットブループリントに実装します。
これで、このウィジェットブループリントの中に先ほどの3つのイベントが増えました。
使い捨てアクタくん
次に、入力用のアクタブループリントを作成します。今回の場合、中身はこのようになっています。
複数の種類のウィジェットに対応できるようにするため、変数のWidgetはObject型のリファレンスにしてあります。
また、この時、
「ポーズ中でもティックする」にはチェックを入れておかないと、ポーズ中に出て来るウィジェットなどに対して動作してくれなくなります。
この手段を使う場合、ウィジェット自身が入力用のアクタをスポーンし、そこに一対一の関係で紐付けをする必要があります。
そして、ウィジェットがビューポートからリムーブされる際、入力用のアクタも同時に破壊されるようにしなければなりません。
ウィジェット側のコンストラクタには、
このように入力用アクタをスポーンして、そこに自分自身のリファレンスを登録させるようにしています。
そして、スポーンした入力用アクタのリファレンスを変数にもっておきます。
あとは、(適当な作りではありますが)それぞれの入力に対応したイベントと、それに応じた動作をウィジェット側に組み込んでみましょう。
決定ボタンを押したときにはウィジェットが消えるので、入力用のアクタにも消えてもらいます。
これで、ウィジェットに対するマウスの入力の可否に関係なく、ウィジェットへのキーボード/ジョイパッドの入力が可能になります。
まとめ
ブループリントインターフェースと入力用アクタを使うことで、ウィジェット自身だけではやりづらい動作や実装も、
色々と組み込みやすくなると思います。
もし面白そうだと思ったら、是非試してみてください。
また、もっと効率のいい方法をご存知の方いらっしゃいましたら、是非教えてください。
ここまでお読み頂き、ありがとうございました。
【UE4】Procedural MIDIでMIDIファイルを元にオブジェクトを生成する
最初に
この記事はMozPacaさんの
mozpaca.hatenablog.com
こちらの記事を読み、触発されて書いたものです。
Procedural MIDIを掘り下げていく過程がわかりやすく書かれているので、
まずはその記事を読んでみてください。
ただし、現在のProcedural MIDIプラグインとはBPノードの見た目や項目数等が異なっていますので、それだけは注意してください。
Procedural MIDIとは
UE4でMIDI関連を取り扱えるようになるプラグインになります。
www.unrealengine.com
こちらからプラグインはダウンロードできますが、
必ず上記のサイトから飛べる「サンプルプロジェクト」もダウンロードするようにしてください!
サンプルプロジェクトは、機能を再確認したりする時にもとても役に立ちます。
まずはサンプルプロジェクトを見てみよう
まずは上記のサンプルプロジェクトを開いてみましょう。
「BP_Readme」の中に書かれているコメントを読んでおくと、今後の応用もやりやすくなると思います。
このサンプルプロジェクト内には、MIDIの初期化などを担当する「BP_Asset_Player」、それを継承し、MIDIメッセージから音を鳴らすのを担当する「BP_MIDI_Player」、
更にそれを継承し、MIDIメッセージを元に視覚オブジェクトを操作する「BP_Visual_MIDI_Player」という3つのオブジェクトがあります。
この構成を元にしてプロジェクトを作ってみましょう。
あと、できればサンプルプロジェクトを実行してみてください。MIDIの音が鳴ると同時に画面内のオブジェクトの色が変わるのがわかると思います。
一体何が起きているのか、自分で調べてみるのも良いと思います。
新しいプロジェクトでブループリントを作ってみる
新しいプロジェクトを立ち上げて、「編集」→「Plugin」を開き、
の「MIDI Plugin」の「Enabled」がチェックされているかを確認しましょう。
チェックされていなかったら、チェックして再起動します。
確認が終わったら、サンプルプロジェクトを参考にして3つのブループリントクラスを作ります。
「BP_Base」と、
それを継承してMIDIから音を鳴らしたりうんぬんする「BP_ObjBase」、
更にそれを継承して、オブジェ生成を担当する「BP_ObjFactory」です。
この上の「MIDIメッセージの中身表示」の部分は検証用に作ったものなので、ご自由にどうぞ。
MIDIメッセージとMIDIファイルの関係
MIDIファイル内にある譜面を再生している時の
「音符」とか「テンポチェンジ」とか「ピッチ変更」とかの指示がMIDIメッセージとして流されます。
つまり、MIDIファイル=譜面とすると、演奏者の「ここでこの音符を鳴らすぞ!」という脳からの命令がMIDIメッセージで、
それが身体に伝わって楽器(MIDI音源)を鳴らす、ということになります。
UE4でMIDIメッセージをゲームなどに利用する際、どんな種類のメッセージに対応して動作させるのかを決めるのは大事です。
どんな種類のメッセージでも受け付けてしまうと、「音符に合わせてオブジェクトを作りたい/動かしたい」と思って実装したものが、
ピッチの変更や楽器の変更などのメッセージで誤動作してしまうからです。
MIDIメッセージの種類はこのように列挙型でまとめられているので、
この中の「Note」でだけ動作するようにブランチを用意するといいと思います。
それではBP_ObjFactoryの「OnMidiEvent」イベントを見てみましょう。
この引数の意味ですが、
・Event Type:このメッセージはどの種類のメッセージか(前述の列挙型)
・Event Channel:何チャンネル目のメッセージか(MIDIはチャンネル数が16あります。つまり同時に16種類の楽器の音が出せるようになっています)0~15の間の値になります。
・Event Data 1:0~127の値になります。Noteメッセージの場合は音の高さになります。それぞれの数値が低い順に鍵盤に割り当てられていると考えてください。
・Event Data 2:0~127の値になります。Noteメッセージの場合は音の強さ(ベロシティ)になります。0の場合、無音になります。
となっています。
ですので今回、自分の場合では
このようにして、音の高さをY軸、音の強さをZ軸にして、さらにチャンネルごとに高さと生成するオブジェの種類を分けることにしました。
ここで大事なのは、「Noteメッセージは、MIDIの音符開始時と終了時の、合計2回流れる」ということです。
例えばベロシティ64の音が鳴る時、鳴り始めにベロシティ64のNoteメッセージが流れ、鳴り終わりにベロシティ0のNoteメッセージが流れます。
ですので、単にNoteメッセージを受け取るだけの実装にすると、予想だにしないタイミングでイベントが発生してしまうことがあります。
先ほどの画像の左上で「!=0」の判定を用意してブランチを挟んでいるのは、このためです。
MIDIファイルを用意して再生してみる
あとはMIDIファイルを用意して再生してみましょう。
Procedural MIDIの続編。弦楽4重奏でおなじみのカノンを元にオブジェクト生成。トラック番号に応じて生成するオブジェクトの種類を変えてみたので、わかりやすいかと。 #UE4 #UE4Study pic.twitter.com/a7iURXyELP
— D.Ohnuma@2月中にアプデ (@dfk_ohnuma) 2017年1月24日
こちらの動作デモではわかりやすいように、弦楽四重奏のカノンのMIDIファイルを使っています。
音を鳴らさずにMIDIファイルを再生する
さて、ここからがある意味本番です。
BP_ObjBaseの、赤く囲った部分の接続を外して、もう一度実行してみましょう。
すると、音は鳴らないのにMIDIファイルの通りにオブジェが生成されているのがわかると思います。
( ^ω^)これがとても美味しいのです。
つまりBGMを別に用意して、BGMと同じテンポでMIDIファイルを作り、同時に再生すれば、
BGMの音楽に合わせた演出やオブジェ生成のためだけのスクリプトファイルとして使うことが出来ます。
MIDIファイルはチャンネル数が16あるので、16チャンネル分の命令を1つのファイルで作ることが出来ます。
どのチャンネルのメッセージなのかをSwitchノードなどで分岐させて実装すれば、
1つのステージ内の敵出現、演出、その他もろもろを1つのMIDIファイルに集約することも可能になると思います。
【UE4】コントローラを振動させる
振動が生む感動
ダメージを受けた時、必殺技を出した時、ボスが倒れた時。
色んなタイミングでコントローラが振動するゲームがコンシューマゲームには多いと思います。
適切なタイミングに用意された振動は、ゲームのもたらす情報を増幅し、
場合によっては感動や陶酔感を生むこともあります。
UE4ではコントローラを振動させる事ができ、しかもそれが案外簡単な方法で出来たので、
このブログ記事で共有させて頂けたらと思います。
フォースフィードバックエフェクトを用意する
実際のところ、コントローラを振動させるには、
このようなノードを用意するだけでOKでした。
各パラメータは以下の通りです。
・ForceFeedbackEffect……振動のパターンプリセット
・Looping……振動パターンがループするか否か
・Tag……タグを持たせたい時に使う
ちなみに、Client Play Force Feedbackで振動を開始した場合、
任意のタイミングでClient Stop Force Feedbackノードを使って振動を停止させることが出来ます。
さて、ノードを用意したばかりではForceFeedbackEffectには何も割り当てられていない場合がほとんどだと思います。
このノードは指定したパターンを再生するわけで、振動パターンが書き込まれたフォースフィードバックエフェクトを指定しなければなにも起きません。
これがフォースフィードバックエフェクトです。
「その他」→「フォースフィードバックエフェクト」で新規作成できます。
コントローラのどの部分を振動操作の対象とするかをチェックボックスで選び、
グラフで横・時間にたいする縦・振動の強さを描きます。
そして出来上がったフォースフィードバックエフェクトを先ほどのノードから指定して、完了です。
これで、実行パルスが通過するタイミングでコントローラが振動します。
フォースフィードバックエフェクトについては、
imoue.hatenablog.com
こちらの記事も参考にするとよいかと思います。
お疲れ様でした。
【コミケ】C91出展します
このたび、個人サークル「大福フューチャーラボ」として、
12月29日(明日ですね)のC91初日に出店させていただきます。
サークル配置は 1日目・西ほ-14b になります。
このブログで書いていた記事の内容をそっくりそのまま応用して作った、
UE4製のゲームとそのサントラが主な頒布物になります。
L.F.O. DLカード 1200円
L.F.O.サントラ DLカード 800円
2つセットで買えば2000円ぴったりなので、是非セットでどうぞ(宣伝)
dfkfuturelab.wixsite.com
↑この特設ページで体験版等もDL出来ますのでよかったらどうぞ
このL.F.O.というゲームなのですが、
音にシンクロする3DSTG、というところでRezを思い浮かべる方も多いと思いますが、
むしろ自分の中では、このゲームの源流は
・ナイトストライカー
・アフターバーナー
・スペースハリアー
・ダライアス
・アウトラン
このあたりのオールドゲームにあります。
そして研究所らしくゲームを作ったときのテーマを言いますと、
・3DSTGに「音とシンクロするゲーム」という要素を加えたらどれぐらい気持ちいいゲームが作れるのか?
・UE4の個人制作でどこまで頑張れるのか?
・学生生活の最後に、自分の作りたいものと、自分のやってきたことの集大成を作りたい!
この辺りが主要なテーマだったような気がします。
ギリギリまで開発を続けましたが、自分の中で納得できるゲームになることが出来ました。
おしゃべりするだけでもいいので、当日はぜひ遊びに来てやってください。
今年はUE4でミートアップに登壇させていただいたり、色々自分の身の回りで変化が大きい年だった気がします。
年明けにもL.F.O.の開発で得た経験を記事にしていきたいと思いますので、是非よろしくお願いいたします。
【UE4】高解像度なスクリーンショットを撮る
はじめに
この記事はちょっとしたTips的なものです。
進捗の必需品・スクリーンショット
ゲームの開発中に、「今こんな感じです」と進捗をネットに上げたりする時、
だいたいはスクリーンショットか動画を見せると思うのですが、
今回はその中でスクリーンショットを用意するときに、
より高画質なものを撮影できる方法を書きたいと思います。
さっそく撮ってみる
というわけでエディタを開きます。
そして、この中にある
「選択ビューポート」でプレイしてみましょう。
プレイ中に好きなタイミングで一時停止をします。
Shift+F1でマウスをビューポートの外へ出して、一時停止のところをクリックすればOKです。
するとこのような画面になるはずです。
では、この状態で「イジェクト」をクリックしますと、
↓
このように、ビューポート内が普段の編集時と同じような見た目になります。
この状態だと、
こうしてビューポートの視点を自由に移動させたり、
こうしてレンダリングされる内容を変更したり、
他にも邪魔なアクタを非表示にしたりできるので、
撮りたいアングルやらなんやらを自由に決めます。
その後、左上のメニューを開いて、
この「高解像度スクリーンショット」を選択しますと、
警告とともにこんな画面が出てきます。
スクリーンショットの解像度をn乗にして撮影できます。
それでは試しに、乗数を1.0、2.0、4.0にしてそれぞれ撮影してみます。
撮影された画像は/Saved/Screenshots/Windowsフォルダへ保存され、
"HighresScreenshot+通し番号.png"という名前で保存されます。
これが1.0
2.0
4.0
まとめ
もちろん乗数を上げれば上げるほど、画像のサイズも大きくなるので容量にはお気をつけください。
こうして撮影した高解像度のスクリーンショットは、フライヤーやポスターに印刷するときに役に立ちそうですね。
技術的な話ではありませんでしたが、ここまでお読み頂きありがとうございました。
【UE4】BGMのテンポに合わせた命令実行機能を作る
この記事は、裏Unreal Engine 4 (UE4) Advent Calendar 2016への参加14日目の記事です。
qiita.com
昨日はyoshikataさんによる
UE4.14・AndroidでVRの実機プレイまでの解説 - Qiitaでした。
曲に合わせて演出したい
例えばゲームで敵が出現するタイミングだったり、演出が起きるタイミングだったり、「ステージ開始から何秒でなにをどうしてこうなって……」と、
画面内でシーケンシャルな動作・演出を行いたいときというのは往々にしてあると思います。
そういう時、単にゲーム内でのことを考えるなら時間で考えれば良いのですが、
これが楽曲のPVを作ったり、音楽に合わせたゲーム内での演出だったらどうでしょう。
何秒で、というよりは「何小節目の何拍目に何をどうしてこうなって」という考え方のほうが、捗りやすいと思います。
ですので、今回の記事ではその仕組みを実装していきます。
(注意:この記事で実装する方法では、楽曲のテンポが一定であることが必要となります。)
また、今回は文字列をいじることも多いのですが、alweiさんの
unrealengine.hatenablog.com
こちらの記事がとても参考になりました。この場を借りて御礼申し上げます。
必要な機能を考える
さて、楽曲にそって処理を行う仕組みを実装するにあたって、必要な機能を考えてみます。
・スクリプトを書き込んだCSVをインポートして、データテーブルとして読み出す
・テンポと小節数、拍数を時間に変換する
・構造体を作り、時間と処理を紐付けして配列にして格納して時間に応じて実行
という感じになると思うのですが、ここで一つ大事になるのは
楽曲に合わせた演出を行う場合、どれだけ細かい音符や珍しい分解能の音符でも対応できる必要がある、ということです。
たとえば楽曲の”キメ”の部分は6分音符になるような楽曲だと、一番細かくても16分音符でしか表現できない仕組みだった場合、
どうしても近似値となる音符で代用する必要が出てきます。その場合、音楽に演出や動きが微妙に合っていないという状況が発生し、
せっかくのテンポに合わせた命令実行という気持ちよさを生み出すための機能が台無しになってしまうことになります。
そのため、今回参考にしたのはBMS(Be-Music Script)の譜面スクリプトの考え方です。
hitkey.nekokan.dyndns.info
これは、PC上で動作する音楽ゲーム「BMS」における譜面スクリプトのフォーマットで、説明するととても長くなるのでお時間のあるときにでもリンク先を読んでみると良いと思います。
このフォーマットの譜面部分は1行で1小節を表記し、
「#WAV01:01」
とある場合、1小節目の頭に音符01が一つ置かれる形となります。(全音符)
「#WAV01:01010101」
とある場合、1小節目の頭から4分音符の間隔ごとに音符01が4つ置かれる形となります。
また、休符は00で表現します。
このように、記述した音符・休符の数に応じてプログラム側で自動的に小節の分割数を決めることが出来るため、
とても自由度の高いスクリプト記述が行えます。
今回の記事で作るスクリプトのシーケンス部分は、このシステムを取り入れています。
スクリプトを作る
まず最初に、構造体を作りましょう。
中身はこれだけです。
そして、これに対応したCSVファイルを作り、ちょっとだけ記述してみました。
私は今回、楽曲ではなくムービーそのものを流すために作ってみたので、最初が「Movie」と書かれていますが、
音楽のために作る場合はSoundとかBGMとかで良いと思います。
今回のスクリプトの仕様としては、
"MovieX":X番目のムービーを指定する(今回は1つしか使わないので0番目だけしか指定してませんが、複数使いたい時は増やせます。)
"BPM":テンポを指定する。
"seqX:Y":X小節目の意味。右側には処理のIDをBMS譜面のような形式で書き込む。Yは同時に2つ以上の処理を行いたい場合などに、seq1:0とseq1:1のように、Yの数字を増やして使う。
となっています。
3小節目は02と03が8分音符のタイミングで交互に、4小節目は16分音符のタイミングで交互に繰り返されているのがわかりますね。
1曲まるまる作るならもっと長いスクリプトファイルになると思います。
スクリプトのために下準備をする
次に、UE4側で下準備をします。
まずはムービー(orサウンド)をスクリプトから指定できるように、文字列に紐付けしたデータテーブルを作っておきます。
そして、スクリプトを読み込んだときに、どの時間にどの処理を行うのかを受け取らなければいけないので、処理用の構造体を作ります。
Time:スクリプトを読み込んで計算された、メディア再生からの経過時間
OperationNumber:処理内容ID
スクリプトを読み込む部分を作る
さて、ここから本番です。まずは読み込むためのBPを作ります。
ちなみに私の作ったBPでは、こんな感じの変数リストになってました。
Media:メディアプレイヤーを予め入れておく配列。たぶんサウンドでやるならAudioComponentか何かになってる
BPM:テンポを入れておく変数
Operation:さっき作った処理用の構造体
forSort:ソートに使ってました
MediaStartTime:再生開始時間を入れておく変数
SequenceStarted:処理が始まっているかどうか
文字列からムービーやらテンポやら処理やら、どれについて書かれた行なのかを判断する必要があります。
うーん、かなり長いですね。ということなので、1つずつ見ていきましょう。
まずはムービーのロード部分です。
データテーブル内のMovieXを検索し、そこに書かれている文字列に対応したメディアをメディアプレイヤーへセットします。
これを楽曲で行う場合は、おそらくSoundXを検索した後、そこに書かれている文字列に対応したサウンドをAudioComponentへセットする形になると思います。
次にBPM設定の部分です。
これは普通ですね。
ではシーケンス部分の読み込み処理を見ていきます。
全体図はこんな感じです。
1行ずつ読み込んで文字列の分解を行い、その結果をOperation配列へ登録。
それが全部終わったら、Timeが短い順にソートする。
という流れになっています。
行ごとの読み込み
99999まで続くForLoopWithBreakが2つありますが、"seqX:Y"におけるXが左側、Yが右側と対応しています。
とはいえいくらなんでも繰り返し回数が多いと思いますので、適当に削ってやっていただいて大丈夫です。
両方から持ってきた数字と"seq"と":"をAppendノードで結合して、データテーブルから値を引っ張ってきます。
文字列の分解
値を引っ張ってきたら、それを分解します。
まずは「IsNumeric」ノードを使って、値となっている文字列が全部数字であるかどうかを確かめます。
次に、文字列の全長を2で割った回数だけForLoopを行い、
2文字ずつ「GetSubstring」ノードで引っ張ってきます。引っ張ってきた2文字をIntにした時、0(="00"、つまり休符)ではない場合は、そのままオペレーション登録へ進みます。
オペレーション登録
処理IDとタイミングが取り出せる状況になったので、タイミングを時間に変換して配列へ登録します。
(60÷BPM)*4=1小節分の長さ
文字列の長さ÷2=小節内の分割単位
1小節の長さ÷小節内の分割単位=1分割単位分の長さ
行ごとの読み込みの左側から取り出せるIndex=何小節目か(A)
文字列分解のForLoopから取り出せるIndex=小節の頭から分割単位いくつ分ズレているか(B)
つまり、
1小節分の長さ×A+1分割単位分の長さ×B=その処理を行うべき経過時間
ということになります。
配列のソート
BPを使った配列のソートについては、こちらのサイト記事を参考にさせていただきました。
ゲームプログラムメモ — Blueprintで配列ソート #UE4Study
処理用の配列を、経過時間が短い順でソートします。
ここまででようやく準備が完了しました。
あとはこれを実行するときの部分になります。
実行部分
まずはBeginPlayに先程作ったスクリプトロードの関数を入れます。
処理を開始する時は、
このようにして、開始時間を記録すると同時にシーケンス処理開始のフラグを立てます。
そして、Tick処理がこちらです。
配列の最初の要素のTimeを確認し、経過時間がそれに到達していたらオペレーション実行のイベントを呼びます。
その後、不要になったそのインデックスを配列から削除します。
オペレーション実行のイベントでは、
このようにSwitch分岐でIDごとに処理を分けます。好きな処理を(99種類までなら)好きなだけ定義することが出来ます。
もちろん、処理IDが多くなればなるほど見た目が複雑になりがちなので、その時は以前の記事のようにマクロを使うなどして可読性を高める必要があると思います。
まとめ
・スクリプトの分解は面倒だけど、理屈がわかれば面白い
・BMSのスクリプトを考えた人は偉大
・これを上手く使えば楽曲のPVを作ったりすることも出来るのでは……?
というわけで、これでこの記事はおしまいです。
ここまで読んで頂き、ありがとうございました。
明日はmonsho1977さんの「ComputeShaderを使ったポストプロセス追加手法」です。
【UE4】リズムに合わせて自動的にActorへイベントが発行される仕組みを作る
今回の記事では、以前ブログに公開したこちらの記事
dfkfuturelab.hatenablog.com
で作った、サウンド管理アクタを利用します。
リズムに合わせて何かをさせたい事、ありませんか
ゲーム内BGMのリズムに合わせて敵を動かしたいとか、パーティクルを出したいとか、その他もろもろ、
リズムに合わせてアクタに何かをさせたい、と思うことは結構多いと思います。
しかし、アクタ毎にテンポを測ってどうのこうの……というのは非効率ですし、タイミングが統一できません。
実は前回の記事を書いた後にらりほまさん(@rarihoma)が
やりたいことによると思うけど、UE4 + FMOD だと小節・拍のタイミングでイベント発行してくれるノードがあったりするので楽。規約をしっかり確認する必要があるというのはその通りです。
— らりほま (@rarihoma) 2016年12月9日
こんなことをツイートされてたので、
「FMODいいなあ、ミドルウェアいいなあ……でも今は使えないし……」
「じゃあ似たような仕組みを作れるかやってみよう!」
と思い立ったら実装できてしまったので、この記事を書きました。
きっかけをもらえて良かったです。
機能を作るにあたって必要なこと
さて、今回はサウンド管理アクタから様々なアクタへとイベントを発行する必要があるのですが、
ゲーム内の全てのアクタにわざわざイベントを送るとなると、あまりに非効率です。そのため、
・イベントを発行してほしいアクタがその旨をサウンド管理アクタへ自己申告する
・そのアクタたちへのリファレンスを発行して欲しい間隔(小節ごととか、4分音符ごととか)ごとに配列に登録しておく
・タイミングが来たら、配列に登録したアクタ達に該当のイベントを発行する
という処理を行えるようにする必要があります。
この時、イベントを発行して欲しいアクタはどんなアクタでも登録できるようにしてやる必要がありますので、
まずはブループリントインターフェースを用意することから初めましょう。
ブループリントインターフェースについては、alweiさんの
unrealengine.hatenablog.com
こちらの記事や、もんしょさんの
もんしょの巣穴blog [UE4] Blueprint Interfaceを使って依存度を下げる
こちらの記事を読むと分かりやすいかと思います。
アクタに持たせるブループリントインターフェースを作る
これだけです。
・MeasureUpdate(小節が変わったタイミングで発行)
・NoteUpdateHalf(2分音符のタイミングで発行)
・NoteUpdate4th(4分音符の以下略)
・NoteUpdate8th(8分音符の以下略)
・NoteUpdate16th(16分音符の以下略)
このイベント発行機能を使いたいアクタには、実装インターフェースにこのインターフェースを指定すればOKです。
サウンド管理アクタ側で準備をする
サウンド管理アクタには、このような配列の変数を作っておきます。
それぞれ、そのタイミングごとにイベントを発行して欲しいアクタをしまっておく配列です。
この中にはアクタを登録するイベントと、アクタを削除するイベントを用意する必要があります。
このように、それぞれの配列に対してイベントを作っていきます。
そして、イベントを発行するための仕組みを作ります。
このサウンド管理アクタの一番最後のマクロの中身はこうなっています。
16分音符が更新されたか→8分音符が更新されたか→4分音符が……
というように、細かい音符から更新チェックを行います。
なぜこうしているかというと、
16分音符が更新されていないときはそれより長い音符は絶対に更新されない、
というように、細かい側の音符が更新されていないことが分かったら、それより分解能が粗い音符については確認する必要がなくなるからです。
(これでほんのちょっとでも負荷が減ると思いたいのです)
そして、それぞれ音符が更新されていたらBoolean変数をtrueにして
このように、イベント発行用の関数の引数に使います。
実は今回スクリーンショットに使っているCleanUp関数は、
もともと効果音のなるタイミングを8分音符や16分音符のタイミングに補正するために用意した関数で、
「更新タイミングのフラグが立っていたら該当する音の配列に登録された効果音を鳴らして、配列をクリアする」
という機能のためにこのような名前になっています。
今回のイベント発行の仕組みは、この関数の中に、
このようにして、
4分音符更新のフラグ(引数から持ってくる)が立っていたら、
ForEachLoopで4分音符のタイミング用の配列に登録された全てのアクタへイベントを発行する
という処理を入れます。
あと、
全体図を見れば分かるのですが、関数の最後にフラグのリセットを行います。
ここまでで、サウンド管理アクタ側の準備は終わりです。
適当なアクタを作って試してみる
では、早速どうでもよさそうなアクタを一つ作ってみましょう。
サウンド管理アクタに「SoundSystem」タグをつけておけば、こうして他のアクタから検索してイベントを発行できます。
4分音符毎にイベントを送ってほしいので、AddActor4thイベントを実行し、自分自身のリファレンスを登録します。
すると、BGMの4分音符のタイミング毎に、下にあるNoteUpdate4thイベントが呼び出され、そこに書いた処理が実行されます。
このアクタは、4分音符毎に「4分音符の更新やで」って画面に表示するようになっています。
次に、別のアクタをもう一つ作ってみます。
クラス名が異なるアクタですが、同じブループリントインターフェースを実装インターフェースに指定しているので、
サウンド管理アクタは同じ処理を行うだけで、そのイベントを発行されたアクタごとが、それぞれ組み込まれた処理を行ってくれるのです。
この2つ目のアクタは、先ほどとは違って4分音符毎に「( ^ω^)おっ」って画面に表示するようになっています。
そして、この2つのアクタをレベル内の適当な場所へ配置します。
では動かしてみる
こちらで動かしてみた様子の動画を見ることが出来ます。
ちゃんと、BGMの4分音符のタイミング毎に、「4分音符の更新やで」「( ^ω^)おっ」の2つのテキストが画面に表示されました。
サウンド管理アクタに用意した4分音符毎のイベント発行処理は無事に行われ、
アクタ毎に設定されているイベントの中身を、それぞれ正しく実行している様子がわかります。
これで確認はできました。
最後に
この機能を使うことで、BGMのテンポに同期した演出を行いやすくすることが出来ると思います。
今回は勢いで作って記事を書いたこともあり、難しい部分も多かったと思いますが、
もし難解すぎるという感想が多かった場合は何らかの機会でまた、詳しく説明できたらと思います。
それでは、読んでいただきましてありがとうございました。