タイトル: レベルを移動する方法
SEOタイトル: UE5 レベル移動完全ガイド (Open Level / Level Streaming / World Partition / Loading Screen)
| この記事の要点 |
|
UE5 でレベル(マップ)を切り替える方法
UE5 でレベル間を移動する方法は大きく分けて 2 種類あります:
- Open Level:現在のレベルを完全に破棄して新しいレベルを開く(ステージ間移動・タイトル → ゲーム)
- Level Streaming / World Partition:大きなマップを分割してロード / アンロード(オープンワールド)
方法 1: Open Level(完全な切替)
Blueprint で実装
Blueprint Graph で右クリック → 「Open Level (by Name)」または「Open Level (by Object Reference)」を配置。
Open Level (By Name) ノード
├── Level Name : Name 型 (例: "L_GameStart")
├── Absolute : true (デフォルト)
└── Options : 追加引数 (例: "?Listen" でリッスンサーバ起動)
Open Level (By Object Reference) ノード
├── Level : World 型 (アセットを直接参照)
├── Absolute : true
└── Options : 追加引数
C++ で実装
#include "Kismet/GameplayStatics.h"
// 名前で開く(FName 型)
UGameplayStatics::OpenLevel(this, FName("L_GameStart"));
// オプション付き
UGameplayStatics::OpenLevel(this, FName("L_GameStart"), true, TEXT("?Listen"));
// Soft Object Reference で開く(推奨:誤タイポ防止)
UPROPERTY(EditAnywhere)
TSoftObjectPtr<UWorld> NextLevel;
void AMyActor::TravelToNext()
{
if (!NextLevel.IsNull())
{
FName LevelName = FName(*NextLevel.GetLongPackageName());
UGameplayStatics::OpenLevel(this, LevelName);
}
}
By Name と By Object Reference の違い
| 項目 | By Name | By Object Reference (Soft) |
|---|---|---|
| 記述 | 文字列 ("L_Stage1") | アセット参照 |
| タイポ耐性 | 低い(実行時エラー) | ★ コンパイル時に検出 |
| パッケージ移動 | パス変更で壊れる | ★ 自動追従 |
| メモリ | 常に文字列分のみ | ★ Soft なら未ロード |
| 推奨 | 動的選択(DataTable 等) | ★ 通常時はこちら |
Open Level 時の挙動と注意
- 全アクターが破棄される(プレイヤーキャラクタ含む)
- GameInstance だけは跨いで保持される → セーブデータ・プレイヤースコアは GameInstance に
- ロード中の数秒〜数十秒、画面が固まるように見える → Loading Screen 推奨
- Streaming Level も自動でアンロードされる
- Multiplayer 環境ではサーバが ClientTravel / ServerTravel を発行する必要あり
Loading Screen の実装
Open Level は同期処理で画面停止するため、ローディング画面を出すのが定番。MoviePlayerを使うのが公式推奨です。
// GameInstance::OnStart() などで PreLoadScreen / MoviePlayer 連携
#include "MoviePlayer.h"
FLoadingScreenAttributes LoadingScreen;
LoadingScreen.bAutoCompleteWhenLoadingCompletes = true;
LoadingScreen.MinimumLoadingScreenDisplayTime = 2.0f;
LoadingScreen.WidgetLoadingScreen = FLoadingScreenAttributes::NewTestLoadingScreenWidget();
GetMoviePlayer()->SetupLoadingScreen(LoadingScreen);
UGameplayStatics::OpenLevel(this, FName("L_GameStart"));
方法 2: Level Streaming(Sub Level の動的ロード)
大きなマップで「現在地周辺だけロード」したい場合、Persistent Level + Sub Level 構成にして、必要なものだけ Load/Unload します。
Window > Levels から Sub Level を登録
- メニュー Window > Levels で Levels パネルを開く
- + Add Sub Level で新規 Sub Level 作成 / 既存追加
- Streaming Method を Always Loaded / Blueprint / World Composition から選択
Blueprint からロード / アンロード
ノード: Load Stream Level (By Name)
├── Level Name : "L_SubArea1"
├── Make Visible After Load : true
├── Should Block on Load : false (非同期)
└── Latent Info (自動)
ノード: Unload Stream Level (By Name)
├── Level Name : "L_SubArea1"
├── Should Block on Unload : false
└── Latent Info (自動)
C++ で実装
#include "Kismet/GameplayStatics.h"
#include "Engine/LatentActionManager.h"
FLatentActionInfo LatentInfo;
UGameplayStatics::LoadStreamLevel(this,
FName("L_SubArea1"),
true, // Make Visible After Load
false, // Should Block on Load
LatentInfo);
// アンロード
UGameplayStatics::UnloadStreamLevel(this,
FName("L_SubArea1"),
LatentInfo,
false);
Level Streaming Volume
プレイヤーが Volume の中に入ったら自動で Sub Level がロードされる仕組み。プログラム不要でエディタ配置だけで動作。
- Place Actors > Volumes > LevelStreamingVolume をシーンに配置
- Volume を選択して、Details > Streaming Levels に対象 Sub Level を追加
- Sub Level の Streaming Method を Blueprint に
方法 3: World Partition (UE5 推奨)
UE5 で導入された新しい大規模ワールド管理。手動の Sub Level 分割が不要になり、エンジンが自動でセル分割&ストリーミング。
- 新規プロジェクトでは大型マップはWorld Partition で作成がデフォルト
- Cell Size(例 25600cm = 256m)でエリア分割
- プレイヤー位置から Loading Range 内のセルを自動ロード
- HLOD(遠景の簡易版)でセル外も視覚的に表示
- One File Per Actor (OFPA) で複数人編集も安全
Data Layer での切替
World Partition 内で「時間帯」「ゲーム進行状態」によってアクター群を切り替えたい場合は Data Layer を使います:
1. World Settings > Data Layers から Data Layer Asset 作成
- 例: "DL_DayScene", "DL_NightScene"
2. シーンのアクターをそれぞれの Data Layer に割り当て
3. Blueprint で Data Layer の状態を切替
ノード: Set Data Layer Runtime State
├── Data Layer : DL_NightScene
└── State : Activated / Loaded / Unloaded
Trigger による Level 移動
// プレイヤーが Trigger Box に入ったら次のレベルへ
UCLASS()
class AStageGoalTrigger : public ATriggerBox
{
GENERATED_BODY()
UPROPERTY(EditAnywhere)
TSoftObjectPtr<UWorld> NextLevel;
virtual void NotifyActorBeginOverlap(AActor* Other) override
{
if (Other && Other->IsA(APawn::StaticClass()))
{
if (!NextLevel.IsNull())
{
FName LevelName = FName(*NextLevel.GetLongPackageName());
UGameplayStatics::OpenLevel(this, LevelName);
}
}
}
};
現在のレベル名を取得
// C++
FString CurrentLevelName = UGameplayStatics::GetCurrentLevelName(this);
UE_LOG(LogTemp, Log, TEXT("Current Level: %s"), *CurrentLevelName);
// Streaming Level の状態取得
ULevelStreaming* Streaming = UGameplayStatics::GetStreamingLevel(this, FName("L_SubArea1"));
if (Streaming && Streaming->IsLevelLoaded())
{
UE_LOG(LogTemp, Log, TEXT("Sub level is loaded"));
}
Blueprint ならGet Current Level Nameノード。
Multiplayer (Listen Server / Dedicated Server) での Travel
| 関数 | 用途 |
|---|---|
UGameplayStatics::OpenLevel | シングル / クライアント側のみ |
GetWorld()->ServerTravel("L_Stage2") | サーバが全クライアントを連れて移動 |
APlayerController::ClientTravel | 個別クライアントの移動 |
UGameplayStatics::OpenLevel(..., "?Listen") | Listen Server として起動 |
Open Level vs Level Streaming の使い分け
| ケース | 推奨 |
|---|---|
| タイトル画面 → ゲーム本編 | Open Level + Loading Screen |
| ステージ 1 クリア → ステージ 2 | Open Level(完全リセット) |
| 巨大オープンワールドの自動管理 | ★ World Partition |
| 建物の中 / 外で別レベル | Level Streaming(Trigger or Volume) |
| 時間帯切替(朝・昼・夜) | Data Layer |
| Multiplayer のステージ進行 | ServerTravel |
パフォーマンスの注意
- Open Level は同期処理で固まる → MoviePlayer / Async Loading で隠す
- 大きな Sub Level の Load は数秒かかる → 事前 Preload を検討
- 頻繁な Load/Unload はメモリフラグメンテーションの原因 → Volume 範囲を適切に
- World Partition の Cell Size を小さくしすぎるとオーバーヘッド増加
- HLOD を必ず生成して、遠景に「何もない」状態を防ぐ
トラブル対処
| 症状 | 原因 | 対処 |
|---|---|---|
| Open Level しても何も起きない | レベル名のタイポ / パッケージ未登録 | Soft Object Reference に切替 |
| Sub Level がロード後すぐ消える | Make Visible After Load 未チェック | true に設定 |
| 移動後にプレイヤー位置がおかしい | Player Start が無い / 複数 | 各レベルに 1 つだけ配置 |
| GameInstance のデータが消える | 誤って GameMode に持たせている | GameInstance に移動 |
| World Partition でアクター見えない | Loading Range 不足 / HLOD 未生成 | World Partition Editor で Build HLODs |
FAQ
Q: Open Level と Restart Level の違いは?
A: Open Level は別レベルへの移動、Restart Level は現レベルをリロード。死亡時のリトライ用にはこちら。
Q: World Partition と Sub Level、新規プロジェクトはどちら?
A: UE5 ではWorld Partition が推奨。Sub Level は UE4 からの移行プロジェクトや小規模で OK。
Q: ロード中の進捗バーを表示したい
A: LoadStreamLevel の Latent Info を使うか、AsyncLoadPrimaryAsset の進捗を取得する Custom Loader を組みます。MoviePlayer の Loading Widget で実装するのが定番。