Level Streaming

今回はLevel Streamingのやり方です。

これだけなら簡単に終わってしまうのですが、それだとつまらないのでちょっと凝ってみます。

まあでも、メインはこれです。

以前も書いたように、Levelというのはスーパーマリオでいうところの1-1とか1-2といったエリア単位で作成します。

通常のLevelの作成方法はEditorの[File] -> [New Level]から作成します。

こうすると今まで編集していたLevelとは別に新しいLevelが作成されます。

そうして1-1のLevel、1-2のLevelと別々に作っていくわけですが、すべてがそれで対応できるわけではありません。

1-1から1-2に進む際には残機表示画面が表示され、背景は隠されます。

その段階で1-1の背景が削除され、1-2が読み込まれて表示されます。

ユーザはその瞬間を見ることができないので、Open LevelによるLevelロードが入ってもそれほど問題ないのです。

しかし、FPSなどの場合は1つのLevelが非常に長いです。

CoDシリーズの場合なら、中東の街に降り立ってから核爆発で主人公がやられるまでが1つのLevelなわけで、この長いLevelをすべてメモリに載せるのはロード時間的にもメモリ容量的にも厳しいわけです。

そこで、フェードインアウトのような場面切り替えをしない方法が必要になってくるのですが、それが今回やるLevel Streamingです。

海外のゲームではエレベータに乗っている時間や先が見えない自動ドアなどでこの手の手法が用いられています。

もちろん、UE4でも比較的簡単に実装できます。

では、やり方を見ていきましょう。

まず、いつものようにBlankプロジェクトを選択してStreamingProjectを作成しましょう。

最初にStreamingを行うLevelを作成しますが、これの作成は[File] -> [New Level]では作成しません。

その方法で作成してから追加することもできるのですが、面倒なので別の方法をとります。

まずは[Window] -> [Levels]を選択してください。Levelsタブのウィンドウが表示されます。

ここにある"Persistent Level"がメインLevelです。

ue036.png

このウィンドウで右クリックをし、コンテキストメニューを表示します。

ここから[Add Level] -> [Create Empty Level]をクリックすると.umapを保存するためのダイアログが表示されます。

ue037.png

名前は適当に、sample01.umapとしておきましょう。

作成するとLevelsウィンドウにsample01というLevelが表示されます。

作成したLevelは[Current Level]と表示されていますが、これは現在このLevelが編集中という意味になります。

オブジェクトなどを追加するとCurrent Levelになっている.umapに配置されることになります。

作成されたのはEmpty Levelなので、ここには何も入っていません。

LevelsウィンドウのLevel名の左側に目のアイコンがありますが、これを閉じるとそのLevelに配置されているものが非表示になります。

Persistent Levelの目を閉じると背景が真っ黒になるでしょう。

次にsample01 Levelにオブジェクトを配置しましょう。

ただ、新規に作成するのではなく、これからやることのためにメインLevelにある椅子とテーブルをsample01 Levelに移動します。

Scene OutlinerでChair2つとTable, Statueを選択し、Levelsのsample01を選択して右クリック、[Move Selected Actors to Level]をクリックします。

ue038.png

すると、選択した4つのActorがsample01 Levelに移動します。

再びPersistent Levelの目を閉じてみるとライトの当たっていない真っ暗な椅子やテーブルが表示されています。

この状態でPlayを実行すると椅子やテーブルが表示されていない状態で始まるはずです。

影だけは表示されていますが、物は表示されておらず、当然当たり判定もありません。

もしも最初から最後までこのサブLevelを表示したいのであれば、コンテキストメニューから[Change Streaming Method]項目を[Blueprint]から[Always Loaded]に切り替えればOKです。

しかし今回のやることはStreamingなので、[Blueprint]のままにしておいてください。

次にStreaming Levelからすこし離れます。LavelsウィンドウでPersistent Levelをダブルクリックして現在の編集Levelとして設定します。

Box Brushをここに配置します。大きさはXYZがそれぞれ、100, 200, 500として、床の中間あたりに配置します。

このオブジェクトは2枚置いて横開きのドアのようにするので、それを踏まえて配置してください。

Brushの状態のまま使うのはあれなので、このBrushをMeshに変換します。

[Details]タブの[Brush Settings]の隠された項目の中にある[Create Static Mesh]ボタンを押します。

Meshの名前を聞かれるので、DoorMeshという名前にでもしておいてください。

DoorMeshに変わると文字列の入ったテクスチャが貼られています。

[Details]タブの[Materials]の項目で適当なマテリアルを設定します。

同じく[Lighting]項目の[Overriden Light Map Res]にチェックを入れます。

これで指定マテリアルで表示される板の完成です。

この板はドアとして扱うため、Blueprintで動作させたいと思います。

このドアのStaticMeshで[Replace With Composited Blueprint]をクリックし、新しいBPである、DoorBPを作成します。

このドアはOpenDoor関数を呼び出すと開き、CloseDoor関数を呼び出すと閉じるように動作させます。

細かな説明は省きますが、追加した関数、変数は以下の通りです。

ue039.png

BeginPlayイベントの処理は以下の通りです。

ue040.png

最後にTickイベントの処理がちょっと複雑ですが、実際はそんなに難しいことをしていません。

ue043.png

BPだと簡単な計算が複雑に見えてしまうのが難点ですね。

OpenDoor関数はMoveYを1.0に、CloseDoor関数はMoveYを-1.0にするだけの命令です。

のちのため、Player Start Actorを+X軸方向に少し移動しておきます。

この状態でゲームを開始するとドアで椅子とテーブルが見えなくなるように2枚のドアを配置してください。

ドアを開くためのTrigger Volumeを作成します。

大きさが100, 400, 500のBox Brushをドアの+X軸面に接するように配置し、Trigger Volumeに変換します。

これをコピーしたものを今度はドアの-X軸面に接するように配置します。

それぞれの名前を"Open Volume", "Close Volume"としておきましょう。

LevelBPを開きます。

LevelBPではTrigger VolumeのBeginOverlapイベントを処理します。

それぞれのVolumeは2枚のドアのOpenDoor関数、またはCloseDoor関数を呼び出すだけです。

設定が完了したらプレイしてみましょう。

プレイヤーがドアに近づくと自動で開き、そこから先に進むと自動で閉まります。

さて、ここからやっと今回のメイン、Level Streamingです。

自動でドアは開くようになりましたが、今のままでは椅子もテーブルも表示されていません。

これでは困るのでドアが開く前にLevelを読み込みます。

使用する命令は"Load Stream Level"関数です。

Open Volumeの接触イベントで、OpenDoor関数を呼び出す前にLoad Stream Level関数を呼び出します。

Level Nameは"sample01"、bool値2つはどちらもtrueにします。

ue044.png

Make Visible After Loadは読み込み完了後に表示するかどうかのフラグです。

Should Block on Loadは読み込みが完了するまで処理をブロックするフラグです。

前者のフラグをtrueにするとオブジェクト生成に時間がかかりますが、falseの場合はオブジェクト生成をどうすればいいんでしょうね?

サブLevelのBP上で生成を行うんでしょうか?よくわかりません。

これでゲームを始めると、ドアの前で少し引っかかってからドアが開くようになります。

ドアが開くとそこにはちゃんと椅子とテーブルが存在しているはずです。

Streamingで読み込んだサブLevelは破棄することも可能です。

まず、再びEmpty Levelを作成します。名前はsample02としておきましょう。

このサブLevelに適当に何か配置します。わかりやすいモデルなら何でもいいでしょう。

このLevelはゲーム開始時には読み込まれていなければいけませんが、Always Loadedにしてしまうと破棄することができません。

なので、メインLevelのBeginPlayイベントで読み込むようにします。Load Stream Level関数を利用するだけです。

ドアを開け、sample01 Levelが有効になった後、ドアが閉まったら一定時間後にsample02 Levelを破棄します。

使用する命令はUnload Stream Levelで、Level Nameにsample02を指定します。

メインLevelのBPは以下のようになります。

ue045.png

ゲームを実行し、ドアを開け、ドアの先に進んでから2秒後にsample02 Levelが削除されます。

ドアを横から回り込んでみると消えるのがわかりやすいです。

というわけで、今回はこれで完了です。

ちょっと凝ったと言っても難しいこともないですし、こんなの凝った内に入らねぇよ!と言われればその通りかもしれません。

とはいえ、Level Streamingの基礎はわかってもらえたのではないかと思います。