はじめに
2024年の夏にこんなのを作りました。
複数のお気に入りのBGMを、勉強中にかけっぱなしにするようなものです。
これの「やり方」を「まとめたい!」と思っていたのですが、参考にしたチュートリアル動画(下記)が20分あって、しかも動画の中の人の手が早いので手数が多くて書く気になれずにおりました。
しかし最近YouTubeの「文字起こし」機能とAIによる翻訳・要約機能を利用すれば、あらすじは把握して作業できることに気が付いたのでようやく書いてみたものです。
▼こちらのチュートリアル動画(約20分、英語)で学びました。
注意点や注記
オリジナルのチュートリアル動画がUE4で実施されていたものを、UE5だとどうなるか、を示したものです(あまり変わりはないです)。
利用したUEバージョン:5.4
本記事公開時のUE最新バージョンは5.5で、この間にも音声再生系のBPノードは拡充されているようです。今となってはこの方法を使わなくても実現できるようになっているような気がします。
直近の音源系ノードはこちらの投稿(↓)がとても参考になると思います。
(美しいまとめ、、、見習いたい。。)


出来上がりのBPノード図
図を見ればわかる人向け(というか自分用)に書くと、
<仕様>
曲が終了するときに音量が小さくなっていく。
その後、次の曲が再生される。
ランダムで再生される。
<作ったもの>
Actor Componentを作る(名:radioComponent)
作成した「radioComponent」の中は以下の通り。
Event Graph(下図1枚目)
関数「SelectNewSong」(下図2枚目)
関数「tryFadeOutOldSong」(下図3枚目)



オリジナルの動画ではこの部分(2:04ごろ)で提示。
▼「radioComponent」はLevelBPにてEvent BeginPlayに接続しました。
Blueprintノードを組んでいきます(長い闘い)
手数が多いです。
前述のオリジナルのチュートリアル動画もご参照ください。
チュートリアル動画では途中で「手戻り」が発生するなどする箇所があります。
本記事ではその「手戻り」部分をスルーしての手順で進めます。
①準備
オリジナルの動画は2:35あたりから。
プロジェクトファイル作成。
【任意】チュートリアル動画ではThird Personテンプレを利用していましたが、私はBlankテンプレート(Emptyのマップ)を利用しました。
【任意】作業フォルダを作成
Blueprint Classを作成:[Actor Component](下図)
「radioComponent」にリネーム


作成した「radioComponent」を開きます。
本記事を書いていたら、スクリーンショットではかなり長くなってしまうことに気が付いたので、以降は動画(とテキストでの補足説明)を用いて進めます。。
②Event Graphでの作業
Begin PlayイベントでSong Listからランダムな曲を選択し、Spawn Sound 2Dノードを利用して曲を再生する基本的なロジックを作成します
[VARIABLES(変数)]追加:songList
- 型は「Sound Base:Object Reference」←四角いさいころのようなものに
- Publicにする(目アイコンをONにする)
2. 作った「songList」をGetで配置し、ノードを2つ繋ぐ
- 「Get (a copy)」ノードに繋ぐ
- 「Last Index」も繋ぐ
3. 「Last Index」ノードを「Random Integer in Range」ノードにつなぐ
- 下の「◎ Max」側につなぐ
4. 「Random Integer in Range」の「Return Value」を上述で作成済みの「GET」に繋ぐ
5. 「Spawn Sound 2D」ノードを追加
- 「Event Begin Play」を接続
- 「Volume Multiplier」(▼の下に隠れてる)を変数にPromoteする
- 変数名は「Volume」にして目のアイコンを開く(Publicにする)
③関数「Select New Song」を編集
曲の長さを取得できないので、対策として曲の終了を検知して新しい曲を再生する仕組みを組みます。
新しい関数「Select New Song」を作成し、ランダムに曲を選択する処理を分離。
ただし、同じ曲が連続しないようにするためのチェックはのちほど追加する予定。
オリジナルの動画は4:00あたりから。
1. songListからGETまでを「Function」にしてしまう(Collapse to Function)
- 「selectNewSong」という関数名にする
- ▼Outputs: `Selected Song`に設定
- ☑ Pure(☑を入れる)
2. 関数化した「SelectNewSong」の中へ(Wクリックで)
- GETノードのソケットを「Promote to Local variable」する
- Promoteした変数名:「provisionalSong」
- 作成した変数「provisionalSong」で「SET」ノードを作り、「Select New Song」と「Return Node」の間にはさむ
- 「Selected Song」には変数「provisional Song(GET)」を差し替える
④Event Graphに戻る
Spawn Sound 2Dノードから曲のDurationを取得し、Delayノードを使用することで曲の終了を待つ方向性に。
また、曲がループ設定になっている場合も考慮し、「Current Song Ref」という変数に現在再生中の曲の参照を格納。
加えてDelay終了後に現在の曲をフェードアウトさせるロジックも追加。
フェードアウト時間「Fade Duration」を変数として定義。
オリジナルの動画では5:22あたりから。
1. 「Select New Song」ノードの「Selected Song」から「Get Duration」ノードを出す
2. 「Delay」ノードを出す
- 「Spawn Sound 2D」と繋ぐ
- 「Get Duration」のノードを「Delay」の「Duration」ソケットに接続
3. 「Spawn Sound 2D」の「Return Value」ソケットをPromote to Variable (SET)
- 変数名:「CurrentSongRef」とする
- この「SET」を「Spawn Sound 2D」と「Delay」の間にはさむ
4. 「Current Song Ref」を設置(GET)し、「Fade Out」ノードを出す
- 「Delay」ノードを「Fade Out」に繋ぐ
- 「Fade Out」の「Fade Out Duration」をPromote to Variable
- Promoteした変数名:「fadeDuration」+目アイコンをONにする
⑤Custom Event 「Change Song」を作成
フェードアウト完了後に新しい曲を開始するためのカスタムイベント「Change Song」を作成します。
Begin Play時からChange Songを呼び出すよう修正。
オリジナルの動画では6:30あたりから。
1. 「Custom Event」ノードを追加:「Change Song」イベント(赤いノード)
- 「Event Begin Play」の後ろに繋ぐ(青いノード)
- 「Spawn Sound 2D」は「Begin Play」から離して、作成した「Change Song」(赤いノード)の後ろに繋ぎ直す。
- 「Delay」ノードの後ろにも「Change Song」を繋ぐ
- 「Fade Out」と変数「CurrentSongRef」、「FadeDuration」を切り取る
2. 切り取った「Fade Out」ノードたちを「Change Song」と「Spawn Sound 2D」の間にはさむ。
変数「fadeDuration」の「▼Default Value」:5(試しに設定)
4. 変数「songList」にいくつか楽曲を設定する
- 「▼Default Value」>「▼SongList」から追加・指定する。
- 利用する楽曲は、同プロジェクト内のフォルダに格納しておく
⑥【任意】PlayerControllerから制御できるように
【オリジナルの動画:9:20あたりより】
オリジナルの動画のようにThridPersonテンプレートから作業を開始した場合はこちらのやり方も。
当方はPlayerControllerを使わず、「Level Blueprint」で「radioComponent」を呼び出す方法で行ってしまったので、スキップしています。。
1. BPクラスを追加:「Player Controller」(名:genericPlayerController)
- 「+Add Component」:作成した「radioComponent」
- [Detailsパネル > ▼Default]に設定済みの楽曲などが表示される2. World Settings
- 「Player Controller」:作成した「genericPlayerController」
ただし、以下の動画の設定はしておくと、参照しているところから設定をいじれるようになるので、これはやっておいてよいかもしれません。
3. 「radioComponent」にて追加設定
- 変数「songList」のタグ設定:「▼ Variable > Category」を「Public」に(手入力)
- 「volume」、「fadeDuration」変数も同様(「Public」にD&Dしている)
- これで「genericPlayerController」やLevel BPから「▼Public」内で設定が見えるように。
▼上の動画の設定をすると、LevelBPからPublicタグをつけた変数を編集できるように
⑦関数「tryFadeOutOldSong」を作成
フェードアウト処理を関数「Try Fade Out Old Song」に分離し、曲が存在しない場合にエラーが発生するのを防ぐためにIsValidノードを追加。
オリジナルの動画では「Begin Play」時の楽曲設定がされてないので「FadeOut」が機能しないので修正をしています。
オリジナルの動画10:30あたりより。
1. 変数「Current Song Ref」:右クリック > [Convert to Validated Get]
-「Change Song」と「Fade Out」ノードの間にはさむ。
2. 「Get Current Song Ref」と「Fade Out」ノードを「Collapse to Function」でまとめる。
- 関数名:tryFadeOutOldSong
* いったんここまででベースラインは出来上がり。
⑧曲の切り替えタイミング調整
曲の切り替えタイミングを調整するため、Delayノードの時間を「曲のDuration - フェードアウト時間」に変更し、フェードイン処理も追加します。
オリジナルの動画11:30あたりより。
1. 「subtract」ノードを変数Durationと「Delay > Duration」の間にはさむ。
- 「subtract」の下のソケットには変数「Fade Duration」(Get)を刺す
2. 「TryFadeOutOldSong」と「Spawn Sound 2D」の間にDelayノードをはさむ。
- 「Duration」には、変数「Fade Duration」を刺す
⑨バグ修正(SelectNewSongの戻り値を再利用)
新しい曲の選択ロジックが2回呼ばれ、異なる曲が選択されるバグを修正するため、「Select New Song」の戻り値を再利用するように変更。
1. Event Graphの「Select New Song」ノードの「Selected Song」を[Promote to Variable]
- 変数名:current Sound Sound Base
-「Delay」ノードと「Spawn Sound 2D」の間にはさむ
2.「Spawn Sound 2D」の「Sound」ソケットに変数「Current Sound Sound Base」を刺す
3. その後ろのある「Delay」ノードに繋がってる[Target - Duration]の`Target`に変数「Current Sound Sound Base」を刺す
⑩FadeOutの成功/失敗判定を組む
フェードアウトが成功したかどうかを判定する出力ピンを「Try Fade Out Old Song」に追加し、Begin Play時の不要なDelayをスキップする処理を追加。
オリジナルの動画15:10あたりより。
1. 「tryFadeOutOldSong」ファンクションのなかを編集
- 「Fade Out」ノードから「Return Node」を生やす
- 「▼Outputs」追加:「isFading?」 (Boolean型, single)
ここで間違えて左パネルの[LOCAL VARIABLE +]から変数を追加しようとしています。
続けて修正している通り「Return Node」を選択し、右パネルの[▼Outputs]にて変数追加するのが正解です。
- Return Node:「〇 is Fading?☑」
- 「〇 is Fading?□」(False)を「GET」の「Current Song Ref」に接続
2. Event Graphに戻り「tryFadeOutOldSong」と「Delay」の間に「Branch」を刺す
- Branchの「Condition」には「is Fading?」を刺す
<以下、上の動画に収め損ねた設定:下図の通りにします>
Branchの
- True : 「Delay」ノードへ
- False: 「Delay」をスキップして次のノード(SET)へ
⑪同じ曲が連続再生されないよう修正
同じ曲が連続して再生されるのを防ぐため、「Select New Song」内で現在再生中の曲と比較し、同じ場合は再度ランダム選択を行うロジックを追加。
オリジナル動画の16:45あたりより。
1. 「Select New Song」ファンクションにて
- 「Current Sound Sound Base」変数(Get)を設置
- 設置した変数から「==」ノードを生やす
- 「==」の下ソケットには変数「Provisional Song」(Get)を接続
2. 「SET(Provisional Song)」ノードから「Branch」を生やす
- Branchの「Condition」は「==」とつなぐ
- True : 「SET(Provisional Song)」の入口に繋ぐ(ループさせる)
- False:「Return Value」へ
⑫おまけ:固定セトリ(曲のセットリスト)方式
今まで作ったのはランダム再生版。
以下、Song Listを順番に再生する方法(かつ、一曲目も固定)。
カスタムソングを再生するための新しいイベント「Play Custom Song」を追加し、Song Listのインデックスを指定することで特定の曲を再生できるようにします。
オリジナルの動画の18:40あたりより。
1. Custom Event `Play Custom Song`を作成
2. `SET(Current Sound Sound Base)`を複製して`Play Custom Song`に繋ぐ
- 出口の白いソケットは`Spawn Sound 2D`に接続(2つ目の動画の冒頭で実施)
3. 変数`Song List`(Get)を設置し、`Get (a copy)`ノードを生やす
- 出口の青いソケットを`SET(Current Sound Sound Base)`に繋ぐ
- 入口にあるミントグリーンのソケットを、`Play Custom Song`の`Dimension 1`に繋ぐ
- `Dimension 1` : 変数名を`SongIndex`に変更(Detailsパネルの「▼Inputs」にて)
▼こちらの動画の2:00頃、青い「Play Custom Song」ノードの変数Dimention1のpromoteを失敗しています。次の次の動画(最後の動画)にてやり直しています(次の動画ではエラーが発生しています。)。
続き
1. Event Begin Playから「Play Custom Song」ノードを生やす
- 「Song Index(ミントグリーン)」に変数「initialSong」(Get)を接続
「▼ Default Value」で「0」になっている=SongListの0番目が指定されている、ということになります。
以上です。
あとがき
・・・疲れた。。
白状すると、途中ちょっとAIの力を借りました。。
(各項目の「何をするか」の概要説明部分。NotebookLMにサマってもらいました。)
本当は「このノードをここにつなぐと、hogehogeになるのでー」とか、「こうしたいときは、この変数に一度この値を格納してー」みたいなことを自分の勉強のためにも書きたいものですが・・・とりあえず「これ見りゃ再現できるよ!」という記事にてご容赦ください。。
追記:あとそういえば。説明動画では出しませんでしたが、楽曲はSuno(AI)で作ったりし始めました。便利。