@wanotaitei さんが開発しているDungeon Template Library(以後DTL) がUE4で使えそうだったので使ってみた。
DTL(ランダム地形生成ライブラリ)とUE4で遊んでみる会 #UE4 #UE4Study pic.twitter.com/un9FMRTf1e
— ai (@ai_9684_dct) May 17, 2019
画像
UE4でDTLを使えるようにする
上記リンクからDTLをcloneしておく。
C++プロジェクトとしてUE4プロジェクトの Source/
以下に library/DTL
ディレクトリを作成。そこに、DTLライブラリの include
以下をコピーする。
UE4プロジェクトを開き直し、 (プロジェクト名)Build.cs
に以下を記述。
PublicIncludePaths.Add(ModuleDirectory + "/library/DTL/"); PrivateDependencyModuleNames.AddRange(new string[] { "Landscape", "LandscapeEditor" });
これで、DTLと、後に使うLandscape関連の関数が利用できるようになる。
Landscapeを操作する関数を実装する
BlueprintFunctionLibraryを継承したクラスを作成し、以下をコピペ。
- DTLLandscapeControlInEditor.h
#pragma once #include "CoreMinimal.h" #include "Kismet/BlueprintFunctionLibrary.h" #include "DTLLandscapeControlInEditor.generated.h" UCLASS() class DTLSAMPLEUE4_TPS_API UDTLLandscapeControlInEditor : public UBlueprintFunctionLibrary { GENERATED_BODY() UFUNCTION(BlueprintCallable, Category = DTL, meta = (HidePin = "worldContextObject_", DefaultToSelf = "worldContextObject_")) static bool perlinNoise(const UObject* worldContextObject_, float scale); };
- DTLLandscapeControlInEditor.cpp
#include "DTLLandscapeControlInEditor.h" #include "EngineUtils.h" #include "Landscape.h" #include "LandscapeInfo.h" #include "LandscapeEditor/Public/LandscapeEditorUtils.h" #include <DTL.hpp> bool UDTLLandscapeControlInEditor::perlinNoise(const UObject* worldContextObject_, float scale) { UWorld* world = worldContextObject_->GetWorld(); for (TActorIterator<ALandscape> actorItr(world); actorItr; ++actorItr) { ALandscape* landscape = *actorItr; if (landscape != nullptr) { // 2: ULandscapeInfoの初期化 ULandscapeInfo::RecreateLandscapeInfo(world, false); FIntRect rect = landscape->GetBoundingRect(); int32 w = rect.Width() + 1; int32 h = rect.Height() + 1; using shape_t = uint16; std::vector<std::vector<shape_t>> matrix(h, std::vector<shape_t>(w, 0)); constexpr double frequency = 6.0; constexpr uint8_t octaves{ 16 }; const uint32_t seed{ static_cast<uint32_t>( rand() ) }; const dtl::utility::PerlinNoise perlin(seed); double frequency_x{ w / frequency }; double frequency_y{ h / frequency }; for (std::size_t row{}; row < h; ++row) for (std::size_t col{}; col < w; ++col) matrix[row][col] = static_cast<shape_t>(50.0 * perlin.octaveNoise(octaves, col / frequency_x, row / frequency_y)); TArray<uint16> Data; Data.Init(0, w * h); for (auto x = 0; x < w; x++) { for (auto y = 0; y < h; y++) { Data[x * h + y] = static_cast<uint16>(FMath::FloorToInt(scale * matrix[y][x])); } } LandscapeEditorUtils::SetHeightmapData(landscape, Data); return true; } } return false; }
エディタ側からコンパイルし、通れば成功。
実装した関数を呼び出すActorを作成
Actorを継承したブループリントクラスを作成。画像のようなBPを組む。この際、EventPerlinNoise
は Call in Editor
フラグにチェックを、Scale
float変数は、Instance Editable
と Expose on Spawn
にチェックを入れる、
作成したActorを 適当にレベルに配置、続いて、Landscapeを作成し、機能別サンプル
から取ってきたLandscape Material
を適当に割り当てて上げれば完成。
まとめ
現在エディタ側からしかLandscapeを操作出来ないが、ランタイムでLandscapeを操作できると嬉しい。また、まだ試してないが、他のダンジョン生成関数との連携は簡単にできそう。