ブループリントでレベル（マップ）管理、音声再生（Unreal Engine 4.25）

# 前提

身内用に書いたものを、暫定的に公開しているものです。何かおこったら閉じるかもしれません。

[前の記事](https://qiita.com/mml/items/5273a7699cdeb9ca21da)に書いた知識（ブループリントの最低限の知識）は持っている、という前提で書いてます。特に説明のない限り、Unreal Engine 4.25 で FirstPerson テンプレートで作成したプロジェクトのレベルブループリントのイベントグラフ上で操作をする前提です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/7689a532-411d-5340-427e-4fc497f9fa06.png)

# レベル（マップ）の操作をする

UE4 ではシーンとかマップに相当するものはレベルと呼ばれます。アプリには複数のレベルを作ることができ、あるレベルから別のレベルに移動（読み込み）することができます。

ちなみに別の記事に書きましたが、UE4（ブループリント）でマップというと、連想配列のことを意味するため、検「マップ」で検索すると連想配列関連の記事がヒットしてしまいます。こっちの意味の「マップ」の記事を探したいときは、検索するときに「レベル」という用語を使うとよいようです。

## レベルの作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a8b71813-a521-686e-2440-ea347604e05c.png)

コンテンツブラウザで右クリックして「レベル」を選びます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/322bc994-8d9c-13f2-b163-a86f0774d198.png)

作成したレベルの名前は変更できます。ここでは SecondLevel としました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/fbcce7f7-3999-7407-5a26-de86bc94a0d3.png)

ダブルクリックすると、作成したレベルを開けます。デフォルトでは何も配置されていない真っ黒な状態になっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/946b1685-badb-69f0-ad33-7ddb571e8bed.png)

ディレクショナルライトを配置して、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/00af81d8-201a-f4af-adb9-d0d495adb5ef.png)

平面を配置して、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/89c76104-7ee8-0842-9f4d-1bb58ca635fe.png)

平面を100倍程度拡大すると上のような感じになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/7124722e-b0e0-d7f3-42a9-66a5830b225b.png)

これで「プレイ」すると、プレイヤー（のポーン）
）が出現して、移動させたり弾を撃ったりできるはずです。

何もしなくてもプレイヤー（のポーン）が自動的に配置されるのは、後述するプロジェクトの設定のところで、デフォルトのプレイヤーに関する設定がなされているためです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0a014031-1318-939b-14b0-f09f8c9e1fee.png)

ムーバブルかつ Simulate Physics を ON にした Cube も追加しました。これは、自分が移動できていることを確認するためのものです。

## デフォルトのレベルを設定する

複数のレベルがあるときに、アプリが軌道したときにデフォルトで読み込むレベルは、プロジェクトの設定で行います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/946d9143-2900-8e92-36a2-27214cda2051.png)

プロジェクトの設定は、編集メニューの中から開けます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/8d68e5e5-d80f-9d0b-5406-35ac289d7507.png)

開いたウィンドウの中の「プロジェクト」から「マップ＆モード」を選ぶと、右側に Default Maps という項目があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/0aabd67d-412d-4bd6-3cd5-1a176a567c11.png)

その中の「ゲームのデフォルトマップ」で選んだレベルが、アプリを起動したときに開かれるレベルになります。ただし、UE4のエディタ上（の選択ビューポート）で「プレイ」すると、プレイを押した時点でエディタに表示されているレベルがそのまま実行されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/cce5ac5a-a285-fc51-f216-8c1431cd8470.png)

「スタンドアローン」で実行することで、デフォルト設定をしたレベルが読み込まれてアプリが始まります。

なお、エディタのスタートアップマップのほうに設定したレベルは、エディタを開いたときに読み込まれます。

## キャラクター（ポーン）の設定について

プロジェクトの設定の「マップ＆モード」の中の Default Modes の Default Pawn Class で設定できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a90888a7-d4ce-605f-75d3-289be17a91b8.png)

FirstPerson テンプレートで作成したプロジェクトの場合、デフォルトでは FirstPersonCharacter が選ばれています。この設定は、レベルによらず共通なので、何も配置されていないからっぽのレベルを作成しても「プレイ」すると、自動的に FirstPersonCharacter が画面内に配置されて、操作できるようになります。

GameMode や Pawn やまわりの詳しいことは、下記のドキュメントを見てください。

- [キャラクターのセットアップ](https://docs.unrealengine.com/ja/Engine/Animation/CharacterSetupOverview/index.html)：公式ドキュメント

## Pawn に関するどうでも良い余談

デフォルトを DefaultPawn にした状態で、SecondLevel に FirstPersonCharacter をコンテンツブラウザから直接配置しても、プレイすると DefaultPawn が使われます。FirstPersonCharacter を直接配置した状態で、デフォルトを FirstPersonCharacter にしても、配置した側の FirstPersonCharacter は無視されて、別の FirstPersonCharacter が勝手に配置されて、勝手に配置されたほうが操作できるようになります。

しかし最初からあるレベルでは、配置されている FirstPersonCharacter を操作できるうえに、それが配置された状態で DefaultPawn をデフォルトにしても、配置されている FirstPersonCharacter が優先されます。配置されている FirstPersonCharacter を削除した状態でデフォルトを DefaultPawn にして、ようやく DefaultPawn が使われるようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/5a831351-211e-2845-274b-b95e225107d5.png)

さんざん調べた結果、どうやら FirstPersonCharacter の詳細の中にある「ポーン」の Auto Process Player を Disable にすると、配置されている FirstPersonCharacter が無視されるようになります。Auto Process Player を Player_0 にすると、ワールドセッティングのほうが無視されて、配置されているポーンのほうが有効になるようです。

これは分からんかったわー。多分 Player_1 とかにしとくと、プレイヤーを2人にすると、2人目が自動的に配置されている FirstPersonCharacter を操作することになりそうです。

というか、ポーン側の設定がワールド設定に優先してしまう仕様はどうなの？

## 別のレベルを開く

新たなレベルを開いて、そこに移動する一番簡単な方法は OpenLevel ノードを使う方法です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/56bf376c-24a7-6f40-4909-e62baf3f90ec.png)

LevelName に開きたいレベルの名前を入れます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/31a73060-5810-4263-faf0-1e0b834f8f75.png)

こんな感じでボックストリガーを設置して、ボックストリガーのブループリントの OnActorBeginOverlap イベントに OpenLevel ノードを追加すると、ボックストリガーにプレイヤーが入ると、SecondLevel に飛ばされます。ただし、OpenLevel はゲームの実行をいったん止めて読み込みをするので、重いレベルを読み込ませると、読み込みが終了して表示されるまで時間がかかることがあります。

## レベルの階層化

「ウィンドウ」のメニューの「レベル」にチェックを入れると、レベルを管理するウィンドウが開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/61d3656b-1370-c006-d554-693073a28353.png)

アプリ内に複数のレベルが存在するときは、この画面でレベル間に階層構造を作って管理することができます。ウィンドウに最初からある「パーシスタントレベル」は最上位の（親）レベルです。FirstPerson テンプレートでプロジェクトを作成した場合は、これにデフォルトの（FirstPersonExample）レベルが割り当てられています（デフォルトのレベルは、先に書いたようにしてプロジェクトの設定で変更できます）。

後述する、レベルの非同期なロードを実現するには、レベルの階層管理が必要のようです（一応 Level Streaming Volume を使うという別の手もあります）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/4003d03b-6cee-af44-cf96-e550ae2fbe9a.png)

新たに作成したレベルを追加すると、上のようにパーシスタントレベルを親として、子レベルとして追加されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/557f3013-9291-2de8-a215-fbc95348833a.png)

レベル名の左にある目のアイコンで、レベルの表示、非表示を切り替えることができます。同時に複数のレベルを表示させることもできます。複数のレベルを表示させた場合、エディタ内に見えているレベルと、編集対象となっているレベルが異なることがあります（編集対象になっているレベルは、レベルウィンドウの中で青色で表示されます）。

また、子レベルのレベルブループリントを開くときは、レベル階層のウィンドウの中のアイコンで開くようにします。エディタの「ブループリント」「レベルブループリントを開く」のメニューでは、常にパーシスタントレベルのレベルブループリントが開かれます。

## レベルを非同期に読み込む

レベルを非同期（ゲームの実行をとめず）に切り替える方法もあります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/3dfcc1fe-58e7-e9f0-b672-e73a0c4a722b.png)

例えば、こんな感じで書けば（ロード画面はないけど）実現できるようです。ただし、いろいろ制約があります。まず FirstPersonExampleMap と SecondLevel はどちらもパーシスタントレベルではない（子レベルである）必要があるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/a5d98f05-f457-62fa-82ab-f6ef0c82c42a.png)

こんな感じのレベル構造にしといて、パーシスタントレベルのレベルブループリントに、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/2fa0fae2-ed34-40f7-6c18-ca7d9934186b.png)

こんな感じのコードを書いて、FirstPersonExampleMap レベルを読み込ませる必要があります。このとき、OpenLevel を使うと、FirstPersonExampleMap がパーシステントレベルに設定されてしまい、非表示への切り替えができなくなるようです。

また、SecondLevel にはポーン（例えば FirstPersonCharacter）をレベル内に配置して、レベルが読み込まれたときにプレイヤーに（たとえば Player_0 に）割り当てるようにコードを書くか、上のほうに書いたようにあらかじめエディタでFirstPersonCharacter を配置して Auto Process Player を Player_0 にしておく必要があるようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/5b6f2149-1d68-352c-17f6-9fe47c7ccef9.png)

このあたり、なかなか複雑なので、興味がある方は下記の偉い方々の記事を参照してください。

- [レベル ストリーミングの概要](https://docs.unrealengine.com/ja/Engine/LevelStreaming/Overview/index.html): 公式記事
- [レベルにまつわるエトセトラ](https://qiita.com/dgtanaka/items/150f037dc734c7f25d4d)
- [シークエンス変移について、レベル、サブレベルについて、ロード画面について](http://miyahuji111.hatenablog.com/entry/2016/07/30/215428)
- [[UE4] レベルストリーミングについて](https://historia.co.jp/archives/4153/)

# 音声の再生

サウンド関係は、下記の記事がとても参考になります。

- [UE4 サウンドデータ再生とAudioComponentについて](https://qiita.com/unknown_ds/items/0d230f5472cf9a1cee57)

以下は、上記の記事のほぼ抜粋です。

## 再生できるファイル

wav, aiff, ogg, flac のいずれです。 mov, mp4 は再生できません。ffmpeg などで変換しておきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/b18b21a6-37fa-ad8f-8d71-b4caf7e29496.png)

再生したい音声ファイルは、UE4のコンテンツブラウザにドラッグドロップします。すると、サウンドウェーブという形式のアセットになり、ブループリント内で参照できるようになります。サウンドウェーブに変換できた音声ファイルは、アイコンが波形になり、クリックすると音声が再生できます。

## とにかく再生する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/96c2bb33-9ef4-faea-d6c2-140dfe9bd6cf.png)

PlaySound2Dノードを使えば再生できます。再生したい音声は、上に書いたようにあらかじめコンテンツブラウザに登録しておく必要があります。SpawnSound2D というノードもあります。そちらを使うと、再生したサウンドに対応する Audio Component オブジェクトが拾えるので、より細かな制御ができます。

PlaySound2D や SpawnSound2D は、BGMの再生のような、どこにいっても同じ音でなってほしい音の再生に向いてます（多分）。

## 位置情報付きで再生する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/423e4703-5260-2447-a429-88dfb0a334a8.png)

PlaySoundAtLocation や SpawnSoundAtLocation を使うと、位置情報付きでサウンドを再生できます。ヘッドフォンで聞くと、再生した位置によって音の聞こえる位置が変わるのが分かります。

## 他のものにくっつけて再生する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/266247/3c8a3b51-b950-381e-fbc6-72836d174587.png)

指定したスタティックメッシュやパーティクルなどのコンポーネントにくっついた状態で再生されます。くっつけた対象がすっとんでいくと、音も一緒にすっとんでいきます。再生した音の位置を能動的に移動させたい場合にも使えます。何らかのコンポーネントを指定する必要があるので、空のアクターを指定することはできません。

なお、サウンドウェーブをブループリントクラス化して、そのブループリントクラス内に移動するコードを書くことで、音を移動させることもできます。

## 動画の再生について

以下の記事を読んでください。

- [レベル内でビデオをプレイする](https://docs.unrealengine.com/ja/Engine/MediaFramework/HowTo/FileMediaSource/index.html): 公式記事

# 続かない

万が一続くとしたら次からは C++ 編になります