なんとなく日誌

覚え書きとか。twitter:https://twitter.com/noronoroxxxxxx

UE4でMOD対応ゲームを作る その4 MAP読み込み

前回までに、MODを作成する基本的な方法を覚えることができた。
今回はMODとして追加した.pakファイルからMAP名を取得して実際にそのMAPを開くことを目指してみる。
noroue4.hatenablog.com



その前に前回の補足を。
補足
前回は
   プロジェクト作成→新規プラグイン「myMOD」追加→.uplugin編集→「myMOD」の中身作成→ゲーム本体のビルド→MODのビルド
という流れだったけど実はこれだと、ゲーム本体のビルドにMODの中身が既に組み込まれちゃってる
つまり、わざわざMODをビルドしなくてもゲーム本体で「open NewWorld」したらNewWorldを開くことができちゃう。
なので、MODフォルダに.upluginだけ入れた状態で本体をビルドしておいたらよかったね。




それでは今日の本題。
C++を使ってMOD内のMAPを開く方法。
ブループリントでの方法は見つからなかったので、C++を使う方法を説明するよ。

準備
UE4C++を使うには、VisualStudioが必要だ。
Microsoftの作っているIDE(ソフトウェア開発ソフト)で、VisualStudio communityという無料バージョンがある。
容量が10GB以上あるので、ダウンロードとインストールにはかなり時間がかかる。余裕をもって準備しておこう。ディスクの空き容量にも注意だ。

動画にしてみたのでこっちも見てね。

【ゆっくり解説】UE4でMOD対応ゲームの作り方 その2




準備ができたら
手段はいくつかあるみたいだけど、今回はそのひとつ、UObjectLibrary::LoadAssetDataFromPath()を使う。
まずは、Epic Games LauncherからUnreal Engine 4.21.1を起動し、新規のC++プロジェクトを作成しよう。

f:id:noroUE4:20190116013658p:plain
UE4エディタの起動
f:id:noroUE4:20190116160748j:plain
新規プロジェクト作成
New Project→ThirdPersonを選んで、プロジェクト名を付けよう。今回は「myCPP」にする。
C++のコードも作成される分、時間がかかるよ。
作成が終わると自動的にUE4EditorとVisualStudioが起動される。
f:id:noroUE4:20190116160811p:plain
C++プロジェクトの初期画面
作成されたプロジェクトの見た目は、ブループリントプロジェクトとほぼ変わりない。
f:id:noroUE4:20190116160934p:plain
VisualStudioの起動
これが起動したVisualStudioの初期画面。
画面の下に緑色のバーが動いていると思うが、生成されたコードを解析している。もうしばらく待とう。
解析が終わったら、ようやくC++に取り掛かろう。

「Source」フォルダ内にいくつかファイルが生成されているが、今回触るのは「myCPPCharacter.h」「myCPPCharacter.cpp」の二つだけだ。
myCPPCharacter.hを開いたら、#includeを追加しよう。

#include "Engine/ObjectLibrary.h"
#include "Kismet/GameplayStatics.h"

それぞれ、UobjectLibraryとUGameplayStaticsを使うのに必要だ。
次に、protected:の一番下に

UFUNCTION(BlueprintCallable, Category = "myLibrary")
	void scanMaps();
UFUNCTION(BlueprintCallable, Category = "myLibrary")
	void openMaps(int32 mapNumber);

TArray<FName> mapNames;

を追加しよう。
「UFUNCTION」はUE4に情報を伝えるためのおまじないで、BlueprintCallableと設定するとブループリントから関数を呼ぶことができるようになる。
Category名は、ブループリントから呼ぶときに表示されるカテゴリ名。好きな名前をつけられる。
今回は、 「scanMaps」「openMaps」という二つの関数と、「mapNames」というマップ名配列の二つを宣言した。

追加するのはこれだけなので、次はmyCPPCharacter.cppを開こう。
一番下に、

void AmyCPPCharacter::scanMaps()
{
	UObjectLibrary* ObjectLibrary = UObjectLibrary::CreateLibrary(UWorld::StaticClass(), false, true);
	ObjectLibrary->LoadAssetDataFromPath(TEXT("/myMOD"));
	TArray<FAssetData> AssetDatas;
	ObjectLibrary->GetAssetDataList(AssetDatas);

	for (int32 i = 0; i < AssetDatas.Num(); ++i)
	{
		mapNames.Add(AssetDatas[i].AssetName);
	}
}

void AmyCPPCharacter::openMaps(int32 mapNumber)
{
	if (mapNames.Num() <= mapNumber)
	{
		return;
	}
	else
	{
		UGameplayStatics::OpenLevel(GetWorld(), mapNames[mapNumber]);
	}
}

を追加する。
UObjectLibraryのLoadAssetDataFromPath関数で「/myMOD」フォルダ内のアセットデータを読み込む。
/myMODは前回作ったMODのフォルダ名だが、このフォルダが存在しなかったらフリーズするので気を付けて。
既存のマップで動作確認したい場合は、「/Game/StarterContent/Maps」のようにするといい。
これでC++の編集は終わり。「Build」→「Build Solution」でビルドしてからUE4エディタに戻ってThirdPersonCharacterのブループリントを開こう。
ThirdPersonCharacterはコンテンツエディタ上で「Content→ThirdPersonCPP→Blueprints」内にあるはずだ。
最初はブループリント全部が見えないので、「Open Full Blueprint Editor」をクリックしよう。
Event Graphを開いたら、右クリックして
「Event BeginPlay」ノードを設置して、Execピンをドラッグして,さっき作った関数「scanMaps」ノードにつなげよう。
同様に、Keyboard Eventの「0」「1」「2」ノードを設置して、Execピンから、さっき作った関数「openMaps」ノードにつなげよう。
それぞれの「openMaps」ノードの入力値は、キーボードイベントと同じ「0」「1」「2」を入れておいてね。

f:id:noroUE4:20190121000107p:plain
ThirdPersonCharacterのブループリント

さあ、これだけでもう完成だ。Compileボタンでコンパイルして、エディタ上でプレイしてみよう。
「/myMOD」フォルダ内にマップがあれば、キーボードの「0」「1」「2」を押してマップを開けるはずだ。

これでMOD内のマップにゲーム内からアクセスできたけど、問題は残っている。
MOD名をあらかじめ知っておかなければこの方法は使えない。
つまり、あらかじめMOD用のフォルダをいくつも作成した上で配布して、ユーザーにはそのフォルダを利用してMODを作ってもらうことになる。
なんだか、スマートじゃないよね?
もっとちゃんとした方法があるのかもしれないけど、これしか見つからなかったんだ。
もし何か見つかったら続きを書くつもり。
それではまた。