diff --git a/DungeonGenerator.uplugin b/DungeonGenerator.uplugin index 8e2e6d8..eab58b9 100644 --- a/DungeonGenerator.uplugin +++ b/DungeonGenerator.uplugin @@ -1,10 +1,10 @@ { "FileVersion": 3, - "Version": 5, - "VersionName": "1.4", + "Version": 6, + "VersionName": "1.4.1", "FriendlyName": "DungeonGenerator", - "Description": "Generates a three-dimensional dungeon.", - "Category": "Other", + "Description": "Procedural 3D dungeon generator plugin. Easy generation of levels, mini-maps and missions.", + "Category": "Procedural", "CreatedBy": "Narcis Software", "CreatedByURL": "https://happy-game-dev.undo.jp/", "DocsURL": "https://github.com/shun126/DungeonGenerator/wiki/", @@ -19,6 +19,9 @@ "Name": "DungeonGenerator", "Type": "Runtime", "LoadingPhase": "Default", + "WhitelistPlatforms": [ + "Win64" + ], "PlatformAllowList": [ "Win64" ] @@ -27,6 +30,9 @@ "Name": "DungeonGeneratorEditor", "Type": "UncookedOnly", "LoadingPhase": "Default", + "WhitelistPlatforms": [ + "Win64" + ], "PlatformAllowList": [ "Win64" ] diff --git a/Source/DungeonGenerator/Private/Core/Debug/Debug.cpp b/Source/DungeonGenerator/Private/Core/Debug/Debug.cpp index 83ba292..cc4f530 100644 --- a/Source/DungeonGenerator/Private/Core/Debug/Debug.cpp +++ b/Source/DungeonGenerator/Private/Core/Debug/Debug.cpp @@ -11,7 +11,7 @@ All Rights Reserved. // ログマクロ #if UE_BUILD_DEBUG + UE_BUILD_DEVELOPMENT + UE_BUILD_TEST + UE_BUILD_SHIPPING > 0 -DEFINE_LOG_CATEGORY(DungeonGenerator); +DEFINE_LOG_CATEGORY(DungeonGeneratorLogger); #else #define NOMINMAX #include diff --git a/Source/DungeonGenerator/Private/Core/Debug/Debug.h b/Source/DungeonGenerator/Private/Core/Debug/Debug.h index 0a15858..cb09067 100644 --- a/Source/DungeonGenerator/Private/Core/Debug/Debug.h +++ b/Source/DungeonGenerator/Private/Core/Debug/Debug.h @@ -30,12 +30,12 @@ All Rights Reserved. // ログマクロ #if UE_BUILD_DEBUG + UE_BUILD_DEVELOPMENT + UE_BUILD_TEST + UE_BUILD_SHIPPING > 0 #include -DECLARE_LOG_CATEGORY_EXTERN(DungeonGenerator, Log, All); -#define DUNGEON_GENERATOR_ERROR(Format, ...) UE_LOG(DungeonGenerator, Error, Format, ##__VA_ARGS__) -#define DUNGEON_GENERATOR_WARNING(Format, ...) UE_LOG(DungeonGenerator, Warning, Format, ##__VA_ARGS__) -#define DUNGEON_GENERATOR_DISPLAY(Format, ...) UE_LOG(DungeonGenerator, Display, Format, ##__VA_ARGS__) -#define DUNGEON_GENERATOR_LOG(Format, ...) UE_LOG(DungeonGenerator, Log, Format, ##__VA_ARGS__) -#define DUNGEON_GENERATOR_VERBOSE(Format, ...) UE_LOG(DungeonGenerator, Verbose, Format, ##__VA_ARGS__) +DECLARE_LOG_CATEGORY_EXTERN(DungeonGeneratorLogger, Log, All); +#define DUNGEON_GENERATOR_ERROR(Format, ...) UE_LOG(DungeonGeneratorLogger, Error, Format, ##__VA_ARGS__) +#define DUNGEON_GENERATOR_WARNING(Format, ...) UE_LOG(DungeonGeneratorLogger, Warning, Format, ##__VA_ARGS__) +#define DUNGEON_GENERATOR_DISPLAY(Format, ...) UE_LOG(DungeonGeneratorLogger, Display, Format, ##__VA_ARGS__) +#define DUNGEON_GENERATOR_LOG(Format, ...) UE_LOG(DungeonGeneratorLogger, Log, Format, ##__VA_ARGS__) +#define DUNGEON_GENERATOR_VERBOSE(Format, ...) UE_LOG(DungeonGeneratorLogger, Verbose, Format, ##__VA_ARGS__) #elif defined(_WINDOWS) && (defined(_DEBUG) || defined(DEBUG)) #define DUNGEON_GENERATOR_ERROR(Format, ...) dungeon::OutputDebugStringWithArgument(Format, ##__VA_ARGS__) #define DUNGEON_GENERATOR_WARNING(Format, ...) dungeon::OutputDebugStringWithArgument(Format, ##__VA_ARGS__) diff --git a/Source/DungeonGenerator/Private/DungeonGenerateActor.cpp b/Source/DungeonGenerator/Private/DungeonGenerateActor.cpp index 9987969..23885ff 100644 --- a/Source/DungeonGenerator/Private/DungeonGenerateActor.cpp +++ b/Source/DungeonGenerator/Private/DungeonGenerateActor.cpp @@ -6,7 +6,7 @@ All Rights Reserved. #include "DungeonGenerateActor.h" #include "DungeonGenerateParameter.h" -#include "DungeonGenerator.h" +#include "DungeonGeneratorCore.h" #include "DungeonMiniMapTextureLayer.h" #include "DungeonTransactionalHierarchicalInstancedStaticMeshComponent.h" #include "Core/Grid.h" @@ -14,6 +14,7 @@ All Rights Reserved. #include "Core/Room.h" #include "Core/Voxel.h" #include "Core/Debug/BuildInfomation.h" +#include "Core/Debug/Debug.h" #include "Core/Math/Vector.h" //#include @@ -49,20 +50,10 @@ ADungeonGenerateActor::ADungeonGenerateActor(const FObjectInitializer& initializ ADungeonGenerateActor::~ADungeonGenerateActor() { - ReleaseHierarchicalInstancedStaticMeshComponents(); + DestroyImplementation(); } -void ADungeonGenerateActor::ReleaseHierarchicalInstancedStaticMeshComponents() -{ - FloorMeshs.Empty(); - SlopeMeshs.Empty(); - WallMeshs.Empty(); - RoomRoofMeshs.Empty(); - AisleRoofMeshs.Empty(); - PillarMeshs.Empty(); -} - -void ADungeonGenerateActor::StartAddInstance(TArray& meshs) +void ADungeonGenerateActor::BeginAddInstance(TArray& meshs) { for (auto mesh : meshs) { @@ -99,52 +90,37 @@ void ADungeonGenerateActor::EndAddInstance(TArray& room, const float gridSize) { - if (IsValid(DungeonGenerator)) - { - if (OnMovePlayerStart.IsBound()) - { - OnMovePlayerStart.Broadcast(DungeonGenerator->GetStartLocation()); - } - else - { - DungeonGenerator->MovePlayerStart(); - } - } + const FVector min = FVector(room->GetLeft(), room->GetTop(), room->GetBackground()) * gridSize; + const FVector max = FVector(room->GetRight(), room->GetBottom(), room->GetForeground()) * gridSize; + return FBox(min, max); } -void ADungeonGenerateActor::PreInitializeComponents() +void ADungeonGenerateActor::PreGenerateImplementation() { - // 親クラスの呼び出し - Super::PreInitializeComponents(); - - // 生成した全アクターを削除 - if (IsValid(DungeonGenerator)) - { - DungeonGenerator->DestroySpawnedActors(); - } + DestroyImplementation(); if (!IsValid(DungeonGenerateParameter)) { - // TODO:パラメータ無効ログを出力してください + DUNGEON_GENERATOR_ERROR(TEXT("DungeonGenerateParameter is not set")); return; } - DungeonGenerator = NewObject(this); - if (!IsValid(DungeonGenerator)) + mDungeonGeneratorCore = std::make_shared(GetWorld()); + if (mDungeonGeneratorCore == nullptr) { - // TODO:無効ログを出力してください + DUNGEON_GENERATOR_ERROR(TEXT("Failed to generate the DungeonGeneratorCore class")); return; } if (InstancedStaticMesh) { - ReleaseHierarchicalInstancedStaticMeshComponents(); + DestroyImplementation(); DungeonGenerateParameter->EachFloorParts([this](const FDungeonMeshParts& meshParts) { @@ -219,45 +195,45 @@ void ADungeonGenerateActor::PreInitializeComponents() } ); - StartAddInstance(FloorMeshs); - StartAddInstance(SlopeMeshs); - StartAddInstance(WallMeshs); - StartAddInstance(RoomRoofMeshs); - StartAddInstance(AisleRoofMeshs); - StartAddInstance(PillarMeshs); + BeginAddInstance(FloorMeshs); + BeginAddInstance(SlopeMeshs); + BeginAddInstance(WallMeshs); + BeginAddInstance(RoomRoofMeshs); + BeginAddInstance(AisleRoofMeshs); + BeginAddInstance(PillarMeshs); // Add - DungeonGenerator->OnAddFloor([this](UStaticMesh* staticMesh, const FTransform& transform) + mDungeonGeneratorCore->OnAddFloor([this](UStaticMesh* staticMesh, const FTransform& transform) { AddInstance(FloorMeshs, staticMesh, transform); OnCreateFloor.Broadcast(transform); } ); - DungeonGenerator->OnAddSlope([this](UStaticMesh* staticMesh, const FTransform& transform) + mDungeonGeneratorCore->OnAddSlope([this](UStaticMesh* staticMesh, const FTransform& transform) { AddInstance(SlopeMeshs, staticMesh, transform); OnCreateSlope.Broadcast(transform); } ); - DungeonGenerator->OnAddWall([this](UStaticMesh* staticMesh, const FTransform& transform) + mDungeonGeneratorCore->OnAddWall([this](UStaticMesh* staticMesh, const FTransform& transform) { AddInstance(WallMeshs, staticMesh, transform); OnCreateWall.Broadcast(transform); } ); - DungeonGenerator->OnAddRoomRoof([this](UStaticMesh* staticMesh, const FTransform& transform) + mDungeonGeneratorCore->OnAddRoomRoof([this](UStaticMesh* staticMesh, const FTransform& transform) { AddInstance(RoomRoofMeshs, staticMesh, transform); OnCreateAisleRoof.Broadcast(transform); } ); - DungeonGenerator->OnAddAisleRoof([this](UStaticMesh* staticMesh, const FTransform& transform) + mDungeonGeneratorCore->OnAddAisleRoof([this](UStaticMesh* staticMesh, const FTransform& transform) { AddInstance(AisleRoofMeshs, staticMesh, transform); OnCreateAisleRoof.Broadcast(transform); } ); - DungeonGenerator->OnAddPillar([this](uint32_t gridHeight, UStaticMesh* staticMesh, const FTransform& transform) + mDungeonGeneratorCore->OnAddPillar([this](uint32_t gridHeight, UStaticMesh* staticMesh, const FTransform& transform) { AddInstance(PillarMeshs, staticMesh, transform); OnCreatePillar.Broadcast(transform); @@ -265,27 +241,38 @@ void ADungeonGenerateActor::PreInitializeComponents() ); // Reset - DungeonGenerator->OnResetDoor([this](AActor* actor, EDungeonRoomProps props) + mDungeonGeneratorCore->OnResetDoor([this](AActor* actor, EDungeonRoomProps props) { OnResetDoor.Broadcast(actor, props); } ); - if (DungeonGenerator->Create(DungeonGenerateParameter)) + if (mDungeonGeneratorCore->Create(DungeonGenerateParameter)) { + EndAddInstance(FloorMeshs); + EndAddInstance(SlopeMeshs); + EndAddInstance(WallMeshs); + EndAddInstance(RoomRoofMeshs); + EndAddInstance(AisleRoofMeshs); + EndAddInstance(PillarMeshs); + MovePlayerStart(); + } + else + { + DUNGEON_GENERATOR_ERROR(TEXT("Failed to generate dungeon")); + DestroyImplementation(); } - - EndAddInstance(FloorMeshs); - EndAddInstance(SlopeMeshs); - EndAddInstance(WallMeshs); - EndAddInstance(RoomRoofMeshs); - EndAddInstance(AisleRoofMeshs); - EndAddInstance(PillarMeshs); } else { - if (DungeonGenerator->Create(DungeonGenerateParameter)) + if (mDungeonGeneratorCore->Create(DungeonGenerateParameter)) { + MovePlayerStart(); + } + else + { + DUNGEON_GENERATOR_ERROR(TEXT("Failed to generate dungeon")); + DestroyImplementation(); } } @@ -293,25 +280,94 @@ void ADungeonGenerateActor::PreInitializeComponents() // ダンジョン生成した乱数を記録 GeneratedRandomSeed = DungeonGenerateParameter->GetGeneratedRandomSeed(); #endif +} - MovePlayerStart(); +void ADungeonGenerateActor::PostGenerateImplementation() +{ + if (mDungeonGeneratorCore == nullptr) + return; + + // refresh navigation system + if (OnRoomCreated.IsBound()) + { + std::shared_ptr generator = mDungeonGeneratorCore->GetGenerator(); + if (generator) + { + UNavigationSystemV1* navigationSystem = UNavigationSystemV1::GetCurrent(GetWorld()); + const float gridSize = DungeonGenerateParameter->GetGridSize(); + + generator->ForEach([this, gridSize, navigationSystem](const std::shared_ptr& room) + { + const FBox box = ToWorldBoundingBox(room, gridSize); + OnRoomCreated.Broadcast(false, static_cast(room->GetParts()), box); + + if (navigationSystem) + { + navigationSystem->AddDirtyArea(box, 0); + } + } + ); + + if (navigationSystem) + { + navigationSystem->Build(); + } + } + } } -void ADungeonGenerateActor::BeginPlay() +void ADungeonGenerateActor::DestroyImplementation() { - Super::BeginPlay(); + if (mDungeonGeneratorCore != nullptr) + { + mDungeonGeneratorCore->DestroySpawnedActors(); + mDungeonGeneratorCore->UnloadStreamLevels(); + mDungeonGeneratorCore.reset(); + } - mPostGenerated = false; + FloorMeshs.Empty(); + SlopeMeshs.Empty(); + WallMeshs.Empty(); + RoomRoofMeshs.Empty(); + AisleRoofMeshs.Empty(); + PillarMeshs.Empty(); + + DungeonMiniMapTextureLayer = nullptr; } -void ADungeonGenerateActor::EndPlay(const EEndPlayReason::Type EndPlayReason) +/* +開始位置PlayerStart,終了位置ADungeonPlayerGoalの位置および +プレイヤー操作のキャラクターを移動します +*/ +void ADungeonGenerateActor::MovePlayerStart() { - if (IsValid(DungeonGenerator)) + if (mDungeonGeneratorCore != nullptr) { - DungeonGenerator->UnloadStreamLevels(); + if (OnMovePlayerStart.IsBound()) + { + OnMovePlayerStart.Broadcast(mDungeonGeneratorCore->GetStartLocation()); + } + else + { + mDungeonGeneratorCore->MovePlayerStart(); + } } +} - Super::EndPlay(EndPlayReason); +void ADungeonGenerateActor::PreInitializeComponents() +{ + // 親クラスの呼び出し + Super::PreInitializeComponents(); + + PreGenerateImplementation(); +} + +void ADungeonGenerateActor::BeginPlay() +{ + // 親クラスの呼び出し + Super::BeginPlay(); + + mPostGenerated = false; } void ADungeonGenerateActor::Tick(float DeltaSeconds) @@ -321,7 +377,7 @@ void ADungeonGenerateActor::Tick(float DeltaSeconds) if (!mPostGenerated) { mPostGenerated = true; - PostGenerate(); + PostGenerateImplementation(); #if !WITH_EDITOR // ティック無効化 @@ -330,9 +386,9 @@ void ADungeonGenerateActor::Tick(float DeltaSeconds) } // 部屋の生成通知 - if (IsValid(DungeonGenerator)) + if (mDungeonGeneratorCore != nullptr) { - DungeonGenerator->AsyncLoadStreamLevels(); + mDungeonGeneratorCore->AsyncLoadStreamLevels(); } #if WITH_EDITORONLY_DATA && (UE_BUILD_SHIPPING == 0) @@ -340,85 +396,82 @@ void ADungeonGenerateActor::Tick(float DeltaSeconds) #endif } -/** -2D空間は(X軸:前 Y軸:右) -3D空間は(X軸:前 Y軸:右 Z軸:上)である事に注意 -*/ -FBox ADungeonGenerateActor::ToWorldBoundingBox(const std::shared_ptr& room, const float gridSize) +void ADungeonGenerateActor::EndPlay(const EEndPlayReason::Type EndPlayReason) { - const FVector min = FVector(room->GetLeft(), room->GetTop(), room->GetBackground()) * gridSize; - const FVector max = FVector(room->GetRight(), room->GetBottom(), room->GetForeground()) * gridSize; - return FBox(min, max); + DestroyImplementation(); + + // 親クラスの呼び出し + Super::EndPlay(EndPlayReason); } -void ADungeonGenerateActor::PostGenerate() +//////////////////////////////////////////////////////////////////////////////////////////////////// +// BluePrint Useful Functions +void ADungeonGenerateActor::GenerateDungeon() { - if (!IsValid(DungeonGenerator)) - return; - - // refresh navigation system - if (OnRoomCreated.IsBound()) - { - std::shared_ptr generator = DungeonGenerator->GetGenerator(); - if (generator) - { - UNavigationSystemV1* navigationSystem = UNavigationSystemV1::GetCurrent(GetWorld()); - const float gridSize = DungeonGenerateParameter->GetGridSize(); - - generator->ForEach([this, gridSize, navigationSystem](const std::shared_ptr& room) - { - const FBox box = ToWorldBoundingBox(room, gridSize); - OnRoomCreated.Broadcast(false, static_cast(room->GetParts()), box); - - if (navigationSystem) - { - navigationSystem->AddDirtyArea(box, 0); - } - } - ); + PreGenerateImplementation(); + PostGenerateImplementation(); +} - if (navigationSystem) - { - navigationSystem->Build(); - } - } - } +void ADungeonGenerateActor::DestroyDungeon() +{ + DestroyImplementation(); } -//////////////////////////////////////////////////////////////////////////////////////////////////// -// BluePrint Useful Functions int32 ADungeonGenerateActor::FindFloorHeight(const float z) const { - if (!IsValid(DungeonGenerator)) + if (mDungeonGeneratorCore == nullptr) return 0; const int32 gridZ = FindVoxelHeight(z); - const std::shared_ptr& generator = DungeonGenerator->GetGenerator(); + const std::shared_ptr& generator = mDungeonGeneratorCore->GetGenerator(); return generator->FindFloor(gridZ); } int32 ADungeonGenerateActor::FindVoxelHeight(const float z) const { - if (DungeonGenerateParameter == nullptr) + if (!IsValid(DungeonGenerateParameter)) return 0; return static_cast(z / DungeonGenerateParameter->GetGridSize()); } -UDungeonMiniMapTextureLayer* ADungeonGenerateActor::GenerateMiniMapTextureLayer(const int32 textureWidth) +UDungeonMiniMapTextureLayer* ADungeonGenerateActor::GenerateMiniMapTextureLayerWithSize(const int32 textureWidth) { if (textureWidth <= 0) return nullptr; + if (!IsValid(DungeonGenerateParameter)) + return nullptr; + const float gridSize = DungeonGenerateParameter->GetGridSize(); DungeonMiniMapTextureLayer = NewObject(this); - if (IsValid(DungeonMiniMapTextureLayer) == false) + if (!IsValid(DungeonMiniMapTextureLayer)) return nullptr; - if (DungeonMiniMapTextureLayer->GenerateMiniMapTexture(DungeonGenerator, textureWidth, gridSize) == false) + if (DungeonMiniMapTextureLayer->GenerateMiniMapTextureWithSize(mDungeonGeneratorCore, textureWidth, gridSize) == false) + DungeonMiniMapTextureLayer = nullptr; + + return DungeonMiniMapTextureLayer; +} + +UDungeonMiniMapTextureLayer* ADungeonGenerateActor::GenerateMiniMapTextureLayerWithScale(const int32 dotScale) +{ + if (dotScale <= 0) + return nullptr; + + if (!IsValid(DungeonGenerateParameter)) + return nullptr; + + const float gridSize = DungeonGenerateParameter->GetGridSize(); + + DungeonMiniMapTextureLayer = NewObject(this); + if (!IsValid(DungeonMiniMapTextureLayer)) return nullptr; + if (DungeonMiniMapTextureLayer->GenerateMiniMapTextureWithScale(mDungeonGeneratorCore, dotScale, gridSize) == false) + DungeonMiniMapTextureLayer = nullptr; + return DungeonMiniMapTextureLayer; } @@ -442,10 +495,10 @@ void ADungeonGenerateActor::DrawDebugInformation() if (!IsValid(DungeonGenerateParameter)) return; - if (!IsValid(DungeonGenerator)) + if (mDungeonGeneratorCore == nullptr) return; - std::shared_ptr generator = DungeonGenerator->GetGenerator(); + std::shared_ptr generator = mDungeonGeneratorCore->GetGenerator(); if (generator == nullptr) return; diff --git a/Source/DungeonGenerator/Private/DungeonGenerator.cpp b/Source/DungeonGenerator/Private/DungeonGeneratorCore.cpp similarity index 78% rename from Source/DungeonGenerator/Private/DungeonGenerator.cpp rename to Source/DungeonGenerator/Private/DungeonGeneratorCore.cpp index e442059..2ec3ebd 100644 --- a/Source/DungeonGenerator/Private/DungeonGenerator.cpp +++ b/Source/DungeonGenerator/Private/DungeonGeneratorCore.cpp @@ -4,7 +4,7 @@ All Rights Reserved. */ -#include "DungeonGenerator.h" +#include "DungeonGeneratorCore.h" #include "DungeonGenerateParameter.h" #include "DungeonDoor.h" #include "DungeonRoomProps.h" @@ -44,12 +44,13 @@ namespace } } -const FName& UDungeonGenerator::GetDungeonGeneratorTag() +const FName& CDungeonGeneratorCore::GetDungeonGeneratorTag() { return DungeonGeneratorTag; } -UDungeonGenerator::UDungeonGenerator() +CDungeonGeneratorCore::CDungeonGeneratorCore(const TWeakObjectPtr& world) + : mWorld(world) { AddStaticMeshEvent addStaticMeshEvent = [this](UStaticMesh* staticMesh, const FTransform& transform) { @@ -68,12 +69,12 @@ UDungeonGenerator::UDungeonGenerator() mOnResetPillar = addPillarStaticMeshEvent; } -bool UDungeonGenerator::Create(const UDungeonGenerateParameter* parameter) +bool CDungeonGeneratorCore::Create(const UDungeonGenerateParameter* parameter) { // Conversion from UDungeonGenerateParameter to dungeon::GenerateParameter if (!IsValid(parameter)) { - DUNGEON_GENERATOR_ERROR(TEXT("ダンジョン生成パラメータを設定してください")); + DUNGEON_GENERATOR_ERROR(TEXT("Set the dungeon generation parameters")); Clear(); } @@ -138,7 +139,7 @@ bool UDungeonGenerator::Create(const UDungeonGenerateParameter* parameter) } } -bool UDungeonGenerator::CreateImpl_AddRoomAsset(const UDungeonGenerateParameter* parameter, const std::shared_ptr& room) +bool CDungeonGeneratorCore::CreateImpl_AddRoomAsset(const UDungeonGenerateParameter* parameter, const std::shared_ptr& room) { parameter->EachDungeonRoomLocator([this, parameter, &room](const FDungeonRoomLocator& dungeonRoomLocator) { @@ -207,11 +208,11 @@ bool UDungeonGenerator::CreateImpl_AddRoomAsset(const UDungeonGenerateParameter* return true; } -void UDungeonGenerator::AddTerrain() +void CDungeonGeneratorCore::AddTerrain() { if (mGenerator == nullptr) { - DUNGEON_GENERATOR_ERROR(TEXT("UDungeonGenerator::Createを呼び出してください")); + DUNGEON_GENERATOR_ERROR(TEXT("CDungeonGeneratorCore::Createを呼び出してください")); return; } @@ -525,7 +526,7 @@ void UDungeonGenerator::AddTerrain() } else { - DUNGEON_GENERATOR_ERROR(TEXT("UDungeonGenerator: CubeBuilderの生成に失敗しました")); + DUNGEON_GENERATOR_ERROR(TEXT("CDungeonGeneratorCore: CubeBuilderの生成に失敗しました")); } #else /* @@ -547,7 +548,7 @@ void UDungeonGenerator::AddTerrain() #endif } -void UDungeonGenerator::SpawnRecastNavMesh() +void CDungeonGeneratorCore::SpawnRecastNavMesh() { if (ARecastNavMesh* navMeshBoundsVolume = FindActor()) { @@ -559,11 +560,11 @@ void UDungeonGenerator::SpawnRecastNavMesh() } } -void UDungeonGenerator::AddObject() +void CDungeonGeneratorCore::AddObject() { if (mGenerator == nullptr) { - DUNGEON_GENERATOR_ERROR(TEXT("UDungeonGenerator::Createを呼び出してください")); + DUNGEON_GENERATOR_ERROR(TEXT("CDungeonGeneratorCore::Createを呼び出してください")); return; } @@ -595,13 +596,13 @@ void UDungeonGenerator::AddObject() } } -void UDungeonGenerator::Clear() +void CDungeonGeneratorCore::Clear() { mGenerator.reset(); mParameter = nullptr; } -FTransform UDungeonGenerator::GetStartTransform() const +FTransform CDungeonGeneratorCore::GetStartTransform() const { const UDungeonGenerateParameter* parameter = mParameter.Get(); if (IsValid(parameter) && mGenerator != nullptr && mGenerator->GetLastError() == dungeon::Generator::Error::Success) @@ -613,7 +614,7 @@ FTransform UDungeonGenerator::GetStartTransform() const return FTransform::Identity; } -FTransform UDungeonGenerator::GetGoalTransform() const +FTransform CDungeonGeneratorCore::GetGoalTransform() const { const UDungeonGenerateParameter* parameter = mParameter.Get(); if (IsValid(parameter) && mGenerator != nullptr && mGenerator->GetLastError() == dungeon::Generator::Error::Success) @@ -625,12 +626,12 @@ FTransform UDungeonGenerator::GetGoalTransform() const return FTransform::Identity; } -FVector UDungeonGenerator::GetStartLocation() const +FVector CDungeonGeneratorCore::GetStartLocation() const { return GetStartTransform().GetLocation(); } -FVector UDungeonGenerator::GetGoalLocation() const +FVector CDungeonGeneratorCore::GetGoalLocation() const { return GetGoalTransform().GetLocation(); } @@ -647,7 +648,7 @@ static inline FBox ToWorldBoundingBox(const UDungeonGenerateParameter* parameter return FBox(min, max); } -FBox UDungeonGenerator::CalculateBoundingBox() const +FBox CDungeonGeneratorCore::CalculateBoundingBox() const { if (mGenerator) { @@ -669,7 +670,7 @@ FBox UDungeonGenerator::CalculateBoundingBox() const return FBox(EForceInit::ForceInitToZero); } -void UDungeonGenerator::MovePlayerStart() +void CDungeonGeneratorCore::MovePlayerStart() { if (APlayerStart* playerStart = FindActor()) { @@ -723,22 +724,7 @@ void UDungeonGenerator::MovePlayerStart() } //////////////////////////////////////////////////////////////////////////////// -UWorld* UDungeonGenerator::FindWorld() const -{ - UWorld* world = GetWorld(); - return world ? world : GetWorldFromGameViewport(); -} - -UWorld* UDungeonGenerator::GetWorldFromGameViewport() -{ - if (FWorldContext* worldContext = GEngine->GetWorldContextFromGameViewport(GEngine->GameViewport)) - return worldContext->World(); - - return nullptr; -} - -//////////////////////////////////////////////////////////////////////////////// -AActor* UDungeonGenerator::SpawnActor(UClass* actorClass, const FName& folderPath, const FTransform& transform, const ESpawnActorCollisionHandlingMethod spawnActorCollisionHandlingMethod) const +AActor* CDungeonGeneratorCore::SpawnActor(UClass* actorClass, const FName& folderPath, const FTransform& transform, const ESpawnActorCollisionHandlingMethod spawnActorCollisionHandlingMethod) const { AActor* actor = SpawnActorDeferred(actorClass, folderPath, transform, spawnActorCollisionHandlingMethod); //ESpawnActorCollisionHandlingMethod::AlwaysSpawn @@ -750,7 +736,7 @@ AActor* UDungeonGenerator::SpawnActor(UClass* actorClass, const FName& folderPat return actor; } -AStaticMeshActor* UDungeonGenerator::SpawnStaticMeshActor(UStaticMesh* staticMesh, const FName& folderPath, const FTransform& transform, const ESpawnActorCollisionHandlingMethod spawnActorCollisionHandlingMethod) const +AStaticMeshActor* CDungeonGeneratorCore::SpawnStaticMeshActor(UStaticMesh* staticMesh, const FName& folderPath, const FTransform& transform, const ESpawnActorCollisionHandlingMethod spawnActorCollisionHandlingMethod) const { AStaticMeshActor* actor = SpawnActorDeferred(AStaticMeshActor::StaticClass(), folderPath, transform, spawnActorCollisionHandlingMethod); if (!IsValid(actor)) @@ -764,7 +750,7 @@ AStaticMeshActor* UDungeonGenerator::SpawnStaticMeshActor(UStaticMesh* staticMes return actor; } -void UDungeonGenerator::SpawnActorOnFloor(UClass* actorClass, const FTransform& transform) const +void CDungeonGeneratorCore::SpawnActorOnFloor(UClass* actorClass, const FTransform& transform) const { AActor* actor = SpawnActor(actorClass, TEXT("Dungeon/Actors"), transform, ESpawnActorCollisionHandlingMethod::AlwaysSpawn); if (IsValid(actor)) @@ -775,7 +761,7 @@ void UDungeonGenerator::SpawnActorOnFloor(UClass* actorClass, const FTransform& } } -void UDungeonGenerator::SpawnDoorActor(UClass* actorClass, const FTransform& transform, EDungeonRoomProps props) const +void CDungeonGeneratorCore::SpawnDoorActor(UClass* actorClass, const FTransform& transform, EDungeonRoomProps props) const { ADungeonDoor* actor = SpawnActorDeferred(actorClass, TEXT("Dungeon/Actors"), transform, ESpawnActorCollisionHandlingMethod::AlwaysSpawn); if (IsValid(actor)) @@ -793,7 +779,7 @@ void UDungeonGenerator::SpawnDoorActor(UClass* actorClass, const FTransform& tra } } -void UDungeonGenerator::SpawnRoomSensorActor( +void CDungeonGeneratorCore::SpawnRoomSensorActor( UClass* actorClass, const dungeon::Identifier& identifier, const FVector& center, @@ -816,12 +802,12 @@ void UDungeonGenerator::SpawnRoomSensorActor( } }; -void UDungeonGenerator::DestroySpawnedActors() const +void CDungeonGeneratorCore::DestroySpawnedActors() const { - DestroySpawnedActors(GetWorld()); + DestroySpawnedActors(mWorld.Get()); } -void UDungeonGenerator::DestroySpawnedActors(UWorld* world) +void CDungeonGeneratorCore::DestroySpawnedActors(UWorld* world) { if (!IsValid(world)) return; @@ -842,70 +828,96 @@ void UDungeonGenerator::DestroySpawnedActors(UWorld* world) } //////////////////////////////////////////////////////////////////////////////// -UTexture2D* UDungeonGenerator::GenerateMiniMapTexture(uint32_t& horizontalScale, uint32_t textureWidthHeight, uint32_t currentLevel) const +UTexture2D* CDungeonGeneratorCore::GenerateMiniMapTextureWithSize(uint32_t& worldToTextureScale, uint32_t textureWidthHeight, uint32_t currentLevel) const { - const UDungeonGenerateParameter* parameter = mParameter.Get(); - if (!IsValid(parameter)) + if (mGenerator->GetLastError() != dungeon::Generator::Error::Success) + return nullptr; + + std::shared_ptr voxel = mGenerator->GetVoxel(); + if (voxel == nullptr) return nullptr; - + + uint32_t length = 1; + if (length < voxel->GetWidth()) + length = voxel->GetWidth(); + if (length < voxel->GetDepth()) + length = voxel->GetDepth(); + worldToTextureScale = static_cast(static_cast(textureWidthHeight) / static_cast(length)); + + return GenerateMiniMapTexture(worldToTextureScale, textureWidthHeight, currentLevel); +} + +UTexture2D* CDungeonGeneratorCore::GenerateMiniMapTextureWithScale(uint32_t& worldToTextureScale, uint32_t dotScale, uint32_t currentLevel) const +{ if (mGenerator->GetLastError() != dungeon::Generator::Error::Success) return nullptr; std::shared_ptr voxel = mGenerator->GetVoxel(); + if (voxel == nullptr) + return nullptr; + + uint32_t length = 1; + if (length < voxel->GetWidth()) + length = voxel->GetWidth(); + if (length < voxel->GetDepth()) + length = voxel->GetDepth(); + const uint32_t textureWidthHeight = length * dotScale; + worldToTextureScale = static_cast(static_cast(textureWidthHeight) / static_cast(length)); + + return GenerateMiniMapTexture(worldToTextureScale, textureWidthHeight, currentLevel); +} + +UTexture2D* CDungeonGeneratorCore::GenerateMiniMapTexture(uint32_t worldToTextureScale, uint32_t textureWidthHeight, uint32_t currentLevel) const +{ + const UDungeonGenerateParameter* parameter = mParameter.Get(); + if (!IsValid(parameter)) + return nullptr; const size_t totalBufferSize = textureWidthHeight * textureWidthHeight; auto pixels = std::make_unique(totalBufferSize); std::memset(pixels.get(), 0x00, totalBufferSize); - horizontalScale = 0; - { - float length = 1.f; - if (length < voxel->GetWidth()) - length = voxel->GetWidth(); - if (length < voxel->GetDepth()) - length = voxel->GetDepth(); - horizontalScale = static_cast(static_cast(textureWidthHeight) / length); - } + std::shared_ptr voxel = mGenerator->GetVoxel(); if (currentLevel > voxel->GetHeight() - 1) currentLevel = voxel->GetHeight() - 1; - auto rect = [&pixels, textureWidthHeight, horizontalScale](const uint32_t x, const uint32_t y, const uint8_t color) -> void + auto rect = [&pixels, textureWidthHeight, worldToTextureScale](const uint32_t x, const uint32_t y, const uint8_t color) -> void { - const uint32_t px = x * horizontalScale; - const uint32_t py = y * horizontalScale; - for (uint32_t oy = py; oy < py + horizontalScale; ++oy) + const uint32_t px = x * worldToTextureScale; + const uint32_t py = y * worldToTextureScale; + for (uint32_t oy = py; oy < py + worldToTextureScale; ++oy) { - for (uint32_t ox = px; ox < px + horizontalScale; ++ox) + for (uint32_t ox = px; ox < px + worldToTextureScale; ++ox) pixels[textureWidthHeight * oy + ox] = color; } }; - auto line = [&pixels, textureWidthHeight, horizontalScale](const uint32_t x, const uint32_t y, const dungeon::Direction::Index dir, const uint8_t color) -> void + auto line = [&pixels, textureWidthHeight, worldToTextureScale](const uint32_t x, const uint32_t y, const dungeon::Direction::Index dir, const uint8_t color) -> void { - uint32_t px = x * horizontalScale; - uint32_t py = y * horizontalScale; + uint32_t px = x * worldToTextureScale; + uint32_t py = y * worldToTextureScale; switch (dir) { case dungeon::Direction::North: - for (uint32_t ox = px; ox < px + horizontalScale; ++ox) + for (uint32_t ox = px; ox < px + worldToTextureScale; ++ox) pixels[textureWidthHeight * py + ox] = color; break; case dungeon::Direction::South: - py += horizontalScale; - for (uint32_t ox = px; ox < px + horizontalScale; ++ox) + py += worldToTextureScale; + for (uint32_t ox = px; ox < px + worldToTextureScale; ++ox) pixels[textureWidthHeight * py + ox] = color; break; case dungeon::Direction::East: - px += horizontalScale; - for (uint32_t oy = py; oy < py + horizontalScale; ++oy) + px += worldToTextureScale; + for (uint32_t oy = py; oy < py + worldToTextureScale; ++oy) pixels[textureWidthHeight * oy + px] = color; break; case dungeon::Direction::West: - for (uint32_t oy = py; oy < py + horizontalScale; ++oy) + for (uint32_t oy = py; oy < py + worldToTextureScale; ++oy) pixels[textureWidthHeight * oy + px] = color; break; @@ -972,8 +984,7 @@ UTexture2D* UDungeonGenerator::GenerateMiniMapTexture(uint32_t& horizontalScale, } } - UTexture2D* generateTexture = UTexture2D::CreateTransient(textureWidthHeight, textureWidthHeight, PF_R8); - //UTexture2D* generateTexture = UTexture2D::CreateTransient(textureWidthHeight, textureWidthHeight, PF_G8); + UTexture2D* generateTexture = UTexture2D::CreateTransient(textureWidthHeight, textureWidthHeight, PF_G8); generateTexture->Filter = TextureFilter::TF_Nearest; { #if UE_VERSION_OLDER_THAN(5, 0, 0) @@ -986,22 +997,21 @@ UTexture2D* UDungeonGenerator::GenerateMiniMapTexture(uint32_t& horizontalScale, mips.BulkData.Unlock(); } generateTexture->AddToRoot(); +#if WITH_EDITOR + generateTexture->Source.Init(textureWidthHeight, textureWidthHeight, 1, 1, ETextureSourceFormat::TSF_G8, pixels.get()); +#endif generateTexture->UpdateResource(); - // 作成した generateTexture を破棄する(ことにする) - //generateTexture->ConditionalBeginDestroy(); - //generateTexture = nullptr; - return generateTexture; } -std::shared_ptr UDungeonGenerator::GetGenerator() const +std::shared_ptr CDungeonGeneratorCore::GetGenerator() const { return mGenerator; } //////////////////////////////////////////////////////////////////////////////////////////////////// -bool UDungeonGenerator::RequestStreamLevel(const FSoftObjectPath& levelPath, const FVector& levelLocation) +bool CDungeonGeneratorCore::RequestStreamLevel(const FSoftObjectPath& levelPath, const FVector& levelLocation) { const auto requestStreamLevel = std::find_if(mRequestLoadStreamLevels.begin(), mRequestLoadStreamLevels.end(), [&levelPath](const LoadStreamLevelParameter& requestStreamLevel) { @@ -1019,7 +1029,7 @@ bool UDungeonGenerator::RequestStreamLevel(const FSoftObjectPath& levelPath, con return true; } -void UDungeonGenerator::AsyncLoadStreamLevels() +void CDungeonGeneratorCore::AsyncLoadStreamLevels() { if (!mRequestLoadStreamLevels.empty()) { @@ -1030,7 +1040,7 @@ void UDungeonGenerator::AsyncLoadStreamLevels() } } -void UDungeonGenerator::SyncLoadStreamLevels() +void CDungeonGeneratorCore::SyncLoadStreamLevels() { for (const auto& requestStreamLevel : mRequestLoadStreamLevels) { @@ -1039,63 +1049,69 @@ void UDungeonGenerator::SyncLoadStreamLevels() mRequestLoadStreamLevels.clear(); } -void UDungeonGenerator::LoadStreamLevel(const FSoftObjectPath& levelPath, const FVector& levelLocation) +void CDungeonGeneratorCore::LoadStreamLevel(const FSoftObjectPath& levelPath, const FVector& levelLocation) { if (!mLoadedStreamLevels.Contains(levelPath)) { - UWorld* world = FindWorld(); - - bool bSuccess; - /*ULevelStreamingDynamic* levelStreaming = */ ULevelStreamingDynamic::LoadLevelInstanceBySoftObjectPtr( - world, - TSoftObjectPtr(levelPath), - levelLocation, - FRotator::ZeroRotator, - bSuccess - ); - if (bSuccess) - { - mLoadedStreamLevels.Emplace(levelPath); - DUNGEON_GENERATOR_LOG(TEXT("Load Level (%s)"), *levelPath.GetLongPackageName()); - } - else + UWorld* world = mWorld.Get(); + if (IsValid(world)) { - DUNGEON_GENERATOR_ERROR(TEXT("Failed to Load Level (%s)"), *levelPath.GetLongPackageName()); + bool bSuccess; + /*ULevelStreamingDynamic* levelStreaming = */ ULevelStreamingDynamic::LoadLevelInstanceBySoftObjectPtr( + world, + TSoftObjectPtr(levelPath), + levelLocation, + FRotator::ZeroRotator, + bSuccess + ); + if (bSuccess) + { + mLoadedStreamLevels.Emplace(levelPath); + DUNGEON_GENERATOR_LOG(TEXT("Load Level (%s)"), *levelPath.GetLongPackageName()); + } + else + { + DUNGEON_GENERATOR_ERROR(TEXT("Failed to Load Level (%s)"), *levelPath.GetLongPackageName()); + } } } } -void UDungeonGenerator::UnloadStreamLevels() +void CDungeonGeneratorCore::UnloadStreamLevels() { SyncLoadStreamLevels(); - UWorld* world = FindWorld(); - - for (const auto& levelPath : mLoadedStreamLevels) + UWorld* world = mWorld.Get(); + if (IsValid(world)) { - FLatentActionInfo LatentInfo; - UGameplayStatics::UnloadStreamLevelBySoftObjectPtr(world, TSoftObjectPtr(levelPath), LatentInfo, false); + for (const auto& levelPath : mLoadedStreamLevels) + { + FLatentActionInfo LatentInfo; + UGameplayStatics::UnloadStreamLevelBySoftObjectPtr(world, TSoftObjectPtr(levelPath), LatentInfo, false); + } + mLoadedStreamLevels.Empty(); } - mLoadedStreamLevels.Empty(); } -void UDungeonGenerator::UnloadStreamLevel(const FSoftObjectPath& levelPath) +void CDungeonGeneratorCore::UnloadStreamLevel(const FSoftObjectPath& levelPath) { - UWorld* world = FindWorld(); - - if (mLoadedStreamLevels.Contains(levelPath)) + UWorld* world = mWorld.Get(); + if (IsValid(world)) { - FLatentActionInfo LatentInfo; - UGameplayStatics::UnloadStreamLevelBySoftObjectPtr(world, TSoftObjectPtr(levelPath), LatentInfo, false); + if (mLoadedStreamLevels.Contains(levelPath)) + { + FLatentActionInfo LatentInfo; + UGameplayStatics::UnloadStreamLevelBySoftObjectPtr(world, TSoftObjectPtr(levelPath), LatentInfo, false); - mLoadedStreamLevels.Remove(levelPath); + mLoadedStreamLevels.Remove(levelPath); + } } } //////////////////////////////////////////////////////////////////////////////////////////////////// #if WITH_EDITOR -void UDungeonGenerator::DrawDebugInformation(const bool showRoomAisleInfomation, const bool showVoxelGridType) const +void CDungeonGeneratorCore::DrawDebugInformation(const bool showRoomAisleInfomation, const bool showVoxelGridType) const { // 部屋と接続情報のデバッグ情報を表示します if (showRoomAisleInfomation) @@ -1122,7 +1138,7 @@ void UDungeonGenerator::DrawDebugInformation(const bool showRoomAisleInfomation, #endif } -void UDungeonGenerator::DrawRoomAisleInformation() const +void CDungeonGeneratorCore::DrawRoomAisleInformation() const { const UDungeonGenerateParameter* parameter = mParameter.Get(); if (!IsValid(parameter)) @@ -1131,63 +1147,73 @@ void UDungeonGenerator::DrawRoomAisleInformation() const check(mGenerator); mGenerator->ForEach([this, parameter](const std::shared_ptr& room) - { - UKismetSystemLibrary::DrawDebugBox( - FindWorld(), - room->GetCenter() * parameter->GetGridSize(), - room->GetExtent() * parameter->GetGridSize(), - FColor::Magenta, - FRotator::ZeroRotator, - 0.f, - 10.f - ); - - UKismetSystemLibrary::DrawDebugSphere( - FindWorld(), - room->GetGroundCenter() * parameter->GetGridSize(), - 10.f, - 12, - FColor::Magenta, - 0.f, - 2.f - ); - }); + { + UWorld* world = mWorld.Get(); + if (IsValid(world)) + { + UKismetSystemLibrary::DrawDebugBox( + world, + room->GetCenter() * parameter->GetGridSize(), + room->GetExtent() * parameter->GetGridSize(), + FColor::Magenta, + FRotator::ZeroRotator, + 0.f, + 10.f + ); + + UKismetSystemLibrary::DrawDebugSphere( + world, + room->GetGroundCenter() * parameter->GetGridSize(), + 10.f, + 12, + FColor::Magenta, + 0.f, + 2.f + ); + } + } + ); mGenerator->EachAisle([this, parameter](const dungeon::Aisle& edge) - { - UKismetSystemLibrary::DrawDebugLine( - FindWorld(), - *edge.GetPoint(0) * parameter->GetGridSize(), - *edge.GetPoint(1) * parameter->GetGridSize(), - FColor::Red, - 0.f, - 5.f - ); - - const FVector start(static_cast(edge.GetPoint(0)->X), static_cast(edge.GetPoint(0)->Y), static_cast(edge.GetPoint(0)->Z)); - const FVector goal(static_cast(edge.GetPoint(1)->X), static_cast(edge.GetPoint(1)->Y), static_cast(edge.GetPoint(1)->Z)); - UKismetSystemLibrary::DrawDebugSphere( - FindWorld(), - start * parameter->GetGridSize() + FVector(parameter->GetGridSize() / 2.f, parameter->GetGridSize() / 2.f, parameter->GetGridSize() / 2.f), - 10.f, - 12, - FColor::Green, - 0.f, - 5.f - ); - UKismetSystemLibrary::DrawDebugSphere( - FindWorld(), - goal * parameter->GetGridSize() + FVector(parameter->GetGridSize() / 2.f, parameter->GetGridSize() / 2.f, parameter->GetGridSize() / 2.f), - 10.f, - 12, - FColor::Red, - 0.f, - 5.f - ); - }); + { + UWorld* world = mWorld.Get(); + if (IsValid(world)) + { + UKismetSystemLibrary::DrawDebugLine( + world, + *edge.GetPoint(0) * parameter->GetGridSize(), + *edge.GetPoint(1) * parameter->GetGridSize(), + FColor::Red, + 0.f, + 5.f + ); + + const FVector start(static_cast(edge.GetPoint(0)->X), static_cast(edge.GetPoint(0)->Y), static_cast(edge.GetPoint(0)->Z)); + const FVector goal(static_cast(edge.GetPoint(1)->X), static_cast(edge.GetPoint(1)->Y), static_cast(edge.GetPoint(1)->Z)); + UKismetSystemLibrary::DrawDebugSphere( + world, + start * parameter->GetGridSize() + FVector(parameter->GetGridSize() / 2.f, parameter->GetGridSize() / 2.f, parameter->GetGridSize() / 2.f), + 10.f, + 12, + FColor::Green, + 0.f, + 5.f + ); + UKismetSystemLibrary::DrawDebugSphere( + world, + goal * parameter->GetGridSize() + FVector(parameter->GetGridSize() / 2.f, parameter->GetGridSize() / 2.f, parameter->GetGridSize() / 2.f), + 10.f, + 12, + FColor::Red, + 0.f, + 5.f + ); + } + } + ); } -void UDungeonGenerator::DrawVoxelGridType() const +void CDungeonGeneratorCore::DrawVoxelGridType() const { const UDungeonGenerateParameter* parameter = mParameter.Get(); if (!IsValid(parameter)) @@ -1196,23 +1222,28 @@ void UDungeonGenerator::DrawVoxelGridType() const check(mGenerator); mGenerator->GetVoxel()->Each([this, parameter](const FIntVector& location, const dungeon::Grid& grid) - { - //if (grid.GetType() == dungeon::Grid::Aisle || grid.GetType() == dungeon::Grid::Slope) - if (grid.GetType() != dungeon::Grid::Type::Empty && grid.GetType() != dungeon::Grid::Type::OutOfBounds) { - const FVector halfGrid(parameter->GetGridSize() / 2.f, parameter->GetGridSize() / 2.f, parameter->GetGridSize() / 2.f); - UKismetSystemLibrary::DrawDebugBox( - FindWorld(), - FVector(location.X, location.Y, location.Z) * parameter->GetGridSize() + halfGrid, - halfGrid * 0.95, - grid.GetTypeColor(), - FRotator::ZeroRotator, - 0.f, - 5.f - ); - } + UWorld* world = mWorld.Get(); + if (IsValid(world)) + { + //if (grid.GetType() == dungeon::Grid::Aisle || grid.GetType() == dungeon::Grid::Slope) + if (grid.GetType() != dungeon::Grid::Type::Empty && grid.GetType() != dungeon::Grid::Type::OutOfBounds) + { + const FVector halfGrid(parameter->GetGridSize() / 2.f, parameter->GetGridSize() / 2.f, parameter->GetGridSize() / 2.f); + UKismetSystemLibrary::DrawDebugBox( + world, + FVector(location.X, location.Y, location.Z) * parameter->GetGridSize() + halfGrid, + halfGrid * 0.95, + grid.GetTypeColor(), + FRotator::ZeroRotator, + 0.f, + 5.f + ); + } + } - return true; - }); + return true; + } + ); } #endif diff --git a/Source/DungeonGenerator/Private/DungeonGeneratorModule.cpp b/Source/DungeonGenerator/Private/DungeonGeneratorModule.cpp index 457cb8e..4c84df4 100644 --- a/Source/DungeonGenerator/Private/DungeonGeneratorModule.cpp +++ b/Source/DungeonGenerator/Private/DungeonGeneratorModule.cpp @@ -6,7 +6,7 @@ All Rights Reserved. #include "DungeonGeneratorModule.h" -#define LOCTEXT_NAMESPACE "DungeonGeneratorModule" +#define LOCTEXT_NAMESPACE "FDungeonGeneratorModule" void FDungeonGeneratorModule::StartupModule() { @@ -18,4 +18,4 @@ void FDungeonGeneratorModule::ShutdownModule() #undef LOCTEXT_NAMESPACE -IMPLEMENT_MODULE(FDungeonGeneratorModule, DungeonGeneratorModule) +IMPLEMENT_MODULE(FDungeonGeneratorModule, DungeonGenerator) diff --git a/Source/DungeonGenerator/Private/DungeonMiniMapTexture.cpp b/Source/DungeonGenerator/Private/DungeonMiniMapTexture.cpp index 3573c33..a33e97d 100644 --- a/Source/DungeonGenerator/Private/DungeonMiniMapTexture.cpp +++ b/Source/DungeonGenerator/Private/DungeonMiniMapTexture.cpp @@ -1,5 +1,5 @@ /* -テクスチャ +Minimap Texture \author Shun Moriya \copyright 2023- Shun Moriya @@ -7,28 +7,44 @@ All Rights Reserved. */ #include "DungeonMiniMapTexture.h" -#include "DungeonGenerator.h" +#include "DungeonGeneratorCore.h" -bool UDungeonMiniMapTexture::GenerateMiniMapTexture(const UDungeonGenerator* dungeonGenerator, const uint32_t textureWidth, const uint8 currentFloor) +bool UDungeonMiniMapTexture::GenerateMiniMapTextureWithSize(const std::shared_ptr& dungeonGeneratorCore, const uint32_t textureWidth, const uint8 currentFloor) { - if (dungeonGenerator == nullptr) + if (dungeonGeneratorCore == nullptr) return false; DestroyMiniMapTexture(); uint32_t horizontalScale; - Texture = dungeonGenerator->GenerateMiniMapTexture(horizontalScale, textureWidth, currentFloor); + Texture = dungeonGeneratorCore->GenerateMiniMapTextureWithSize(horizontalScale, textureWidth, currentFloor); if (IsValid(Texture) == false) return false; - Texture->AddToRoot(); - GeneratedScale = horizontalScale; GeneratedScaleVector.Set(GeneratedScale, GeneratedScale); return true; } +bool UDungeonMiniMapTexture::GenerateMiniMapTextureWithScale(const std::shared_ptr& dungeonGeneratorCore, const uint32_t dotScale, const uint8 currentFloor) +{ + if (dungeonGeneratorCore == nullptr) + return false; + + DestroyMiniMapTexture(); + + uint32_t horizontalScale; + Texture = dungeonGeneratorCore->GenerateMiniMapTextureWithScale(horizontalScale, dotScale, currentFloor); + if (IsValid(Texture) == false) + return false; + + GeneratedScale = horizontalScale; + GeneratedScaleVector.Set(horizontalScale, horizontalScale); + + return true; +} + void UDungeonMiniMapTexture::DestroyMiniMapTexture() { if (IsValid(Texture)) diff --git a/Source/DungeonGenerator/Private/DungeonMiniMapTextureLayer.cpp b/Source/DungeonGenerator/Private/DungeonMiniMapTextureLayer.cpp index dc38d8c..9270981 100644 --- a/Source/DungeonGenerator/Private/DungeonMiniMapTextureLayer.cpp +++ b/Source/DungeonGenerator/Private/DungeonMiniMapTextureLayer.cpp @@ -1,5 +1,5 @@ /* -階層毎に生成されたミニマップテクスチャクラス +Minimap texture classes generated per layer \author Shun Moriya \copyright 2023- Shun Moriya @@ -8,15 +8,31 @@ All Rights Reserved. #include "DungeonMiniMapTextureLayer.h" #include "DungeonMiniMapTexture.h" -#include "DungeonGenerator.h" +#include "DungeonGeneratorCore.h" #include "Core/Generator.h" -bool UDungeonMiniMapTextureLayer::GenerateMiniMapTexture(const UDungeonGenerator* dungeonGenerator, const uint32_t textureWidth, const float gridSize) +FVector2D UDungeonMiniMapTextureLayer::GetTextureSize() const noexcept { - if (dungeonGenerator == nullptr) + if (DungeonMiniMapTextures.Num() == 0) + return FVector2D::ZeroVector; + + const UDungeonMiniMapTexture* dungeonMiniMapTexture = DungeonMiniMapTextures[0]; + if (!IsValid(dungeonMiniMapTexture)) + return FVector2D::ZeroVector; + + const UTexture2D* texture = dungeonMiniMapTexture->GetTexture(); + if (!IsValid(dungeonMiniMapTexture)) + return FVector2D::ZeroVector; + + return FVector2D(texture->GetSizeX(), texture->GetSizeY()); +} + +bool UDungeonMiniMapTextureLayer::GenerateMiniMapTextureWithSize(const std::shared_ptr& dungeonGeneratorCore, const uint32_t textureWidth, const float gridSize) +{ + if (dungeonGeneratorCore == nullptr) return false; - mGenerator = dungeonGenerator->GetGenerator(); + mGenerator = dungeonGeneratorCore->GetGenerator(); if (mGenerator == nullptr) return false; @@ -29,10 +45,38 @@ bool UDungeonMiniMapTextureLayer::GenerateMiniMapTexture(const UDungeonGenerator if (IsValid(miniMapTexture)) { const int32_t height = floorHeight[i]; - if (miniMapTexture->GenerateMiniMapTexture(dungeonGenerator, textureWidth, height) == false) + if (miniMapTexture->GenerateMiniMapTextureWithSize(dungeonGeneratorCore, textureWidth, height) == false) miniMapTexture = nullptr; } + DungeonMiniMapTextures.Add(miniMapTexture); + } + + mGridSize = gridSize; + + return true; +} + +bool UDungeonMiniMapTextureLayer::GenerateMiniMapTextureWithScale(const std::shared_ptr& dungeonGeneratorCore, const uint32_t dotScale, const float gridSize) +{ + if (dungeonGeneratorCore == nullptr) + return false; + mGenerator = dungeonGeneratorCore->GetGenerator(); + if (mGenerator == nullptr) + return false; + + const std::vector& floorHeight = mGenerator->GetFloorHeight(); + DungeonMiniMapTextures.Reset(floorHeight.size()); + + for (uint8_t i = 0; i < floorHeight.size(); ++i) + { + UDungeonMiniMapTexture* miniMapTexture = NewObject(this); + if (IsValid(miniMapTexture)) + { + const int32_t height = floorHeight[i]; + if (miniMapTexture->GenerateMiniMapTextureWithScale(dungeonGeneratorCore, dotScale, height) == false) + miniMapTexture = nullptr; + } DungeonMiniMapTextures.Add(miniMapTexture); } @@ -75,3 +119,12 @@ FVector2D UDungeonMiniMapTextureLayer::ToRelativeAndFloor(uint8& floor, const FV return ToRelative(location); } + +FVector2D UDungeonMiniMapTextureLayer::ToNormalize(const FVector& location) const +{ + const FVector2D& textureSize = GetTextureSize(); + if (textureSize.IsNearlyZero()) + return FVector2D::ZeroVector; + + return ToRelative(location) / textureSize; +} diff --git a/Source/DungeonGenerator/Private/DungeonRoomSensor.cpp b/Source/DungeonGenerator/Private/DungeonRoomSensor.cpp index 1a7b7e4..e2f6865 100644 --- a/Source/DungeonGenerator/Private/DungeonRoomSensor.cpp +++ b/Source/DungeonGenerator/Private/DungeonRoomSensor.cpp @@ -5,7 +5,7 @@ All Rights Reserved. */ #include "DungeonRoomSensor.h" -#include "DungeonGenerator.h" +#include "DungeonGeneratorCore.h" #include "Core/Identifier.h" #include #include @@ -15,13 +15,13 @@ All Rights Reserved. namespace { - static bool ForceShowDebugInfomation = false; + static bool ForceShowDebugInformation = false; } #endif const FName& ADungeonRoomSensor::GetDungeonGeneratorTag() { - return UDungeonGenerator::GetDungeonGeneratorTag(); + return CDungeonGeneratorCore::GetDungeonGeneratorTag(); } const TArray& ADungeonRoomSensor::GetDungeonGeneratorTags() @@ -61,7 +61,7 @@ void ADungeonRoomSensor::Tick(float DeltaSeconds) Super::Tick(DeltaSeconds); // cppcheck-suppress [knownConditionTrueFalse] - if (ShowDebugInfomation || ForceShowDebugInfomation) + if (ShowDebugInfomation || ForceShowDebugInformation) { TArray output; output.Add(TEXT("Identifier:") + FString::FromInt(Identifier)); diff --git a/Source/DungeonGenerator/Public/DungeonGenerateActor.h b/Source/DungeonGenerator/Public/DungeonGenerateActor.h index c4d5976..c5e6fee 100644 --- a/Source/DungeonGenerator/Public/DungeonGenerateActor.h +++ b/Source/DungeonGenerator/Public/DungeonGenerateActor.h @@ -11,7 +11,7 @@ All Rights Reserved. #include "DungeonGenerateActor.generated.h" // 前方宣言 -class UDungeonGenerator; +class CDungeonGeneratorCore; class UDungeonGenerateParameter; class UDungeonMiniMapTextureLayer; class UDungeonTransactionalHierarchicalInstancedStaticMeshComponent; @@ -46,11 +46,31 @@ class DUNGEONGENERATOR_API ADungeonGenerateActor : public AActor */ virtual ~ADungeonGenerateActor(); + /** + Generate new dungeon + */ + UFUNCTION(BlueprintCallable, Category = "DungeonGenerator") + void GenerateDungeon(); + /** + Destroy dungeon + */ UFUNCTION(BlueprintCallable, Category = "DungeonGenerator") - int32 FindFloorHeight(const float z) const; + void DestroyDungeon(); + /** + Finds the floor from the world Z coordinate + \param[in] z Z coordinate of world + \return floor + */ + UFUNCTION(BlueprintCallable, Category = "DungeonGenerator") + int32 FindFloorHeight(const float z) const; + /** + Finds the Z coordinate of the grid from the world Z coordinate + \param[in] z Z coordinate of world + \return Z coordinate of the grid + */ UFUNCTION(BlueprintCallable, Category = "DungeonGenerator") int32 FindVoxelHeight(const float z) const; @@ -58,7 +78,13 @@ class DUNGEONGENERATOR_API ADungeonGenerateActor : public AActor Generates a texture layer for the minimap */ UFUNCTION(BlueprintCallable, Category = "DungeonGenerator") - UDungeonMiniMapTextureLayer* GenerateMiniMapTextureLayer(const int32 textureWidth); + UDungeonMiniMapTextureLayer* GenerateMiniMapTextureLayerWithSize(const int32 textureWidth = 512); + + /** + Generates a texture layer for the minimap + */ + UFUNCTION(BlueprintCallable, Category = "DungeonGenerator") + UDungeonMiniMapTextureLayer* GenerateMiniMapTextureLayerWithScale(const int32 dotScale = 1); /** Get a texture layer for a generated minimap @@ -76,9 +102,7 @@ class DUNGEONGENERATOR_API ADungeonGenerateActor : public AActor #endif private: - void ReleaseHierarchicalInstancedStaticMeshComponents(); - - static void StartAddInstance(TArray& meshs); + static void BeginAddInstance(TArray& meshs); static void AddInstance(TArray& meshs, const UStaticMesh* staticMesh, const FTransform& transform); @@ -86,10 +110,11 @@ class DUNGEONGENERATOR_API ADungeonGenerateActor : public AActor static inline FBox ToWorldBoundingBox(const std::shared_ptr& room, const float gridSize); + void PreGenerateImplementation(); + void PostGenerateImplementation(); + void DestroyImplementation(); void MovePlayerStart(); - void PostGenerate(); - protected: UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "DungeonGenerator") UDungeonGenerateParameter* DungeonGenerateParameter = nullptr; @@ -182,11 +207,6 @@ class DUNGEONGENERATOR_API ADungeonGenerateActor : public AActor UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Transient, Category = "DungeonGenerator|Detail") FString LicenseId; - // Cache of the UIDungeonMiniMapTextureLayer - UPROPERTY(BlueprintReadOnly, Transient, Category = "DungeonGenerator") - UDungeonGenerator* DungeonGenerator; - // TObjectPtr not used for UE4 compatibility - #if WITH_EDITORONLY_DATA && (UE_BUILD_SHIPPING == 0) // Displays debugging information on room and connection information UPROPERTY(EditAnywhere, BlueprintReadOnly, Transient, Category = "DungeonGenerator|Debug") @@ -205,5 +225,8 @@ class DUNGEONGENERATOR_API ADungeonGenerateActor : public AActor #endif private: + // Cache of the UIDungeonMiniMapTextureLayer + std::shared_ptr mDungeonGeneratorCore; + bool mPostGenerated = false; }; diff --git a/Source/DungeonGenerator/Public/DungeonGenerateParameter.h b/Source/DungeonGenerator/Public/DungeonGenerateParameter.h index 17f3ba4..6b15148 100644 --- a/Source/DungeonGenerator/Public/DungeonGenerateParameter.h +++ b/Source/DungeonGenerator/Public/DungeonGenerateParameter.h @@ -388,7 +388,7 @@ class DUNGEONGENERATOR_API UDungeonGenerateParameter : public UObject UDungeonRoomAsset* DungeonRoomAsset; // TObjectPtr not used for UE4 compatibility - friend class UDungeonGenerator; + friend class CDungeonGeneratorCore; }; // aka: SelectActorParts, SelectRandomActorParts diff --git a/Source/DungeonGenerator/Public/DungeonGenerator.h b/Source/DungeonGenerator/Public/DungeonGeneratorCore.h similarity index 69% rename from Source/DungeonGenerator/Public/DungeonGenerator.h rename to Source/DungeonGenerator/Public/DungeonGeneratorCore.h index 3998690..79e644a 100644 --- a/Source/DungeonGenerator/Public/DungeonGenerator.h +++ b/Source/DungeonGenerator/Public/DungeonGeneratorCore.h @@ -13,7 +13,6 @@ All Rights Reserved. #include #include #include -#include "DungeonGenerator.generated.h" // Forward declaration class UDungeonGenerateParameter; @@ -31,11 +30,8 @@ namespace dungeon /* Dungeon generate class */ -UCLASS() -class DUNGEONGENERATOR_API UDungeonGenerator : public UObject +class DUNGEONGENERATOR_API CDungeonGeneratorCore final : public std::enable_shared_from_this { - GENERATED_BODY() - public: using AddStaticMeshEvent = std::function; using AddPillarStaticMeshEvent = std::function; @@ -52,12 +48,14 @@ class DUNGEONGENERATOR_API UDungeonGenerator : public UObject /** constructor */ - UDungeonGenerator(); + explicit CDungeonGeneratorCore(const TWeakObjectPtr& world); + CDungeonGeneratorCore(const CDungeonGeneratorCore&) = delete; + CDungeonGeneratorCore& operator=(const CDungeonGeneratorCore&) = delete; /** destructor */ - virtual ~UDungeonGenerator() = default; + ~CDungeonGeneratorCore() = default; // event void OnAddFloor(const AddStaticMeshEvent& func); @@ -120,12 +118,21 @@ class DUNGEONGENERATOR_API UDungeonGenerator : public UObject /** Generates a minimap texture of the generated dungeon - \param[out] horizontalScale Scale value to convert from world coordinates to texture coordinates - \param[in] textureWidthHeight Width of texture to be generated (height equals width) - \param[in] currentLevel Criteria for floor height to be generated + \param[out] worldToTextureScale Scale value to convert from world coordinates to texture coordinates + \param[in] textureWidthHeight Width of texture to be generated (height equals width) + \param[in] currentLevel Criteria for floor height to be generated \return texture object */ - UTexture2D* GenerateMiniMapTexture(uint32_t& horizontalScale, uint32_t textureWidthHeight, uint32_t currentLevel) const; + UTexture2D* GenerateMiniMapTextureWithSize(uint32_t& worldToTextureScale, uint32_t textureWidthHeight, uint32_t currentLevel) const; + + /** + Generates a minimap texture of the generated dungeon + \param[out] worldToTextureScale Scale value to convert from world coordinates to texture coordinates + \param[in] textureScale Scale of texture to be generated (height equals width) + \param[in] currentLevel Criteria for floor height to be generated + \return texture object + */ + UTexture2D* GenerateMiniMapTextureWithScale(uint32_t& worldToTextureScale, uint32_t textureScale, uint32_t currentLevel) const; /** Get dungeon generation core object. @@ -142,10 +149,6 @@ class DUNGEONGENERATOR_API UDungeonGenerator : public UObject void AddTerrain(); void AddObject(); - //////////////////////////////////////////////////////////////////////////// - UWorld* FindWorld() const; - static UWorld* GetWorldFromGameViewport(); - //////////////////////////////////////////////////////////////////////////// AActor* SpawnActor(UClass* actorClass, const FName& folderPath, const FTransform& transform, const ESpawnActorCollisionHandlingMethod spawnActorCollisionHandlingMethod = ESpawnActorCollisionHandlingMethod::AlwaysSpawn) const; template T* SpawnActor(const FName& folderPath, const FTransform& transform, const ESpawnActorCollisionHandlingMethod spawnActorCollisionHandlingMethod = ESpawnActorCollisionHandlingMethod::AlwaysSpawn) const; @@ -181,6 +184,9 @@ class DUNGEONGENERATOR_API UDungeonGenerator : public UObject void LoadStreamLevel(const FSoftObjectPath& levelPath, const FVector& levelLocation); void UnloadStreamLevel(const FSoftObjectPath& levelPath); + //////////////////////////////////////////////////////////////////////////// + UTexture2D* GenerateMiniMapTexture(uint32_t worldToTextureScale, uint32_t textureWidthHeight, uint32_t currentLevel) const; + //////////////////////////////////////////////////////////////////////////// #if WITH_EDITOR void DrawRoomAisleInformation() const; @@ -188,8 +194,9 @@ class DUNGEONGENERATOR_API UDungeonGenerator : public UObject #endif private: - std::shared_ptr mGenerator; + TWeakObjectPtr mWorld; TWeakObjectPtr mParameter; + std::shared_ptr mGenerator; AddStaticMeshEvent mOnAddFloor; AddStaticMeshEvent mOnAddSlope; @@ -222,64 +229,63 @@ class DUNGEONGENERATOR_API UDungeonGenerator : public UObject friend class FDungeonGenerateEditorModule; }; -inline void UDungeonGenerator::OnAddFloor(const AddStaticMeshEvent& func) +inline void CDungeonGeneratorCore::OnAddFloor(const AddStaticMeshEvent& func) { mOnAddFloor = func; } -inline void UDungeonGenerator::OnAddSlope(const AddStaticMeshEvent& func) +inline void CDungeonGeneratorCore::OnAddSlope(const AddStaticMeshEvent& func) { mOnAddSlope = func; } -inline void UDungeonGenerator::OnAddWall(const AddStaticMeshEvent& func) +inline void CDungeonGeneratorCore::OnAddWall(const AddStaticMeshEvent& func) { mOnAddWall = func; } -inline void UDungeonGenerator::OnAddRoomRoof(const AddStaticMeshEvent& func) +inline void CDungeonGeneratorCore::OnAddRoomRoof(const AddStaticMeshEvent& func) { mOnAddRoomRoof = func; } -inline void UDungeonGenerator::OnAddAisleRoof(const AddStaticMeshEvent& func) +inline void CDungeonGeneratorCore::OnAddAisleRoof(const AddStaticMeshEvent& func) { mOnAddAisleRoof = func; } -inline void UDungeonGenerator::OnAddPillar(const AddPillarStaticMeshEvent& func) +inline void CDungeonGeneratorCore::OnAddPillar(const AddPillarStaticMeshEvent& func) { mOnResetPillar = func; } -inline void UDungeonGenerator::OnResetTorch(const ResetActorEvent& func) +inline void CDungeonGeneratorCore::OnResetTorch(const ResetActorEvent& func) { mOnResetTorch = func; } #if 0 -inline void UDungeonGenerator::OnAddChandelier(const ResetActorEvent& func) +inline void CDungeonGeneratorCore::OnAddChandelier(const ResetActorEvent& func) { mOnResetChandelier = func; } #endif -inline void UDungeonGenerator::OnResetDoor(const ResetDoorEvent& func) +inline void CDungeonGeneratorCore::OnResetDoor(const ResetDoorEvent& func) { mOnResetDoor = func; } template -inline T* UDungeonGenerator::SpawnActor(const FName& folderPath, const FTransform& transform, const ESpawnActorCollisionHandlingMethod spawnActorCollisionHandlingMethod) const +inline T* CDungeonGeneratorCore::SpawnActor(const FName& folderPath, const FTransform& transform, const ESpawnActorCollisionHandlingMethod spawnActorCollisionHandlingMethod) const { - AActor* actor = SpawnActor(T::StaticClass(), folderPath, transform, spawnActorCollisionHandlingMethod); - return Cast(actor); + return Cast(SpawnActor(T::StaticClass(), folderPath, transform, spawnActorCollisionHandlingMethod)); } template -inline T* UDungeonGenerator::SpawnActorDeferred(UClass* actorClass, const FName& folderPath, const FTransform& transform, const ESpawnActorCollisionHandlingMethod spawnActorCollisionHandlingMethod) const +inline T* CDungeonGeneratorCore::SpawnActorDeferred(UClass* actorClass, const FName& folderPath, const FTransform& transform, const ESpawnActorCollisionHandlingMethod spawnActorCollisionHandlingMethod) const { - UWorld* world = GetWorld(); + UWorld* world = mWorld.Get(); if (!IsValid(world)) return nullptr; @@ -297,15 +303,27 @@ inline T* UDungeonGenerator::SpawnActorDeferred(UClass* actorClass, const FName& } template -inline T* UDungeonGenerator::FindActor() +inline T* CDungeonGeneratorCore::FindActor() { - const TActorIterator iterator(GetWorld()); - return iterator ? *iterator : nullptr; + UWorld* world = mWorld.Get(); + if (IsValid(world)) + { + const TActorIterator iterator(world); + if (iterator) + return *iterator; + } + return nullptr; } template -inline const T* UDungeonGenerator::FindActor() const +inline const T* CDungeonGeneratorCore::FindActor() const { - const TActorIterator iterator(GetWorld()); - return iterator ? *iterator : nullptr; + UWorld* world = mWorld.Get(); + if (IsValid(world)) + { + const TActorIterator iterator(world); + if (iterator) + return *iterator; + } + return nullptr; } diff --git a/Source/DungeonGenerator/Public/DungeonMiniMapTexture.h b/Source/DungeonGenerator/Public/DungeonMiniMapTexture.h index 042c5a5..d628b3c 100644 --- a/Source/DungeonGenerator/Public/DungeonMiniMapTexture.h +++ b/Source/DungeonGenerator/Public/DungeonMiniMapTexture.h @@ -1,5 +1,5 @@ /* -Minimap Textures +Minimap Texture \author Shun Moriya \copyright 2023- Shun Moriya @@ -10,7 +10,7 @@ All Rights Reserved. #include #include "DungeonMiniMapTexture.generated.h" -class UDungeonGenerator; +class CDungeonGeneratorCore; class UTexture2D; /** @@ -54,7 +54,12 @@ class DUNGEONGENERATOR_API UDungeonMiniMapTexture : public UObject /** Generates a minimap texture */ - bool GenerateMiniMapTexture(const UDungeonGenerator* dungeonGenerator, const uint32_t textureWidth, const uint8 currentFloor); + bool GenerateMiniMapTextureWithSize(const std::shared_ptr& dungeonGeneratorCore, const uint32_t textureWidth, const uint8 currentFloor); + + /** + Generates a minimap texture + */ + bool GenerateMiniMapTextureWithScale(const std::shared_ptr& dungeonGeneratorCore, const uint32_t textureScale, const uint8 currentFloor); /** Destroy minimap textures diff --git a/Source/DungeonGenerator/Public/DungeonMiniMapTextureLayer.h b/Source/DungeonGenerator/Public/DungeonMiniMapTextureLayer.h index 3f4e3cc..99ed1da 100644 --- a/Source/DungeonGenerator/Public/DungeonMiniMapTextureLayer.h +++ b/Source/DungeonGenerator/Public/DungeonMiniMapTextureLayer.h @@ -11,7 +11,7 @@ All Rights Reserved. #include "DungeonMiniMapTextureLayer.generated.h" class ADungeonGenerateActor; -class UDungeonGenerator; +class CDungeonGeneratorCore; class UDungeonMiniMapTexture; class UTexture2D; @@ -39,6 +39,12 @@ class DUNGEONGENERATOR_API UDungeonMiniMapTextureLayer : public UObject */ virtual ~UDungeonMiniMapTextureLayer() = default; + /** + Get UDungeonMiniMapTexture from height + */ + UFUNCTION(BlueprintCallable, Category = "DungeonGenerator") + FVector2D GetTextureSize() const noexcept; + /** Get the total number of levels */ @@ -75,14 +81,25 @@ class DUNGEONGENERATOR_API UDungeonMiniMapTextureLayer : public UObject UFUNCTION(BlueprintCallable, Category = "DungeonGenerator") FVector2D ToRelativeAndFloor(uint8& floor, const FVector& location) const; + /** + Converts from world coordinates to normalized coordinates (0 to 1) + */ + UFUNCTION(BlueprintCallable, Category = "DungeonGenerator") + FVector2D ToNormalize(const FVector& location) const; + private: /** Generates a minimap texture */ - bool GenerateMiniMapTexture(const UDungeonGenerator* dungeonGenerator, const uint32_t textureWidth, const float gridSize); + bool GenerateMiniMapTextureWithSize(const std::shared_ptr& dungeonGeneratorCore, const uint32_t textureWidth, const float gridSize); + + /** + Generates a minimap texture + */ + bool GenerateMiniMapTextureWithScale(const std::shared_ptr& dungeonGeneratorCore, const uint32_t textureScale, const float gridSize); private: - // 階層毎のダンジョンミニマップテクスチャ + // Dungeon minimap textures for each level UPROPERTY(BlueprintReadOnly, Category = "DungeonGenerator", meta = (AllowPrivateAccess = "true")) TArray DungeonMiniMapTextures; // TObjectPtr not used for UE4 compatibility @@ -94,6 +111,7 @@ class DUNGEONGENERATOR_API UDungeonMiniMapTextureLayer : public UObject float mGridSize = 1.f; friend class ADungeonGenerateActor; + friend class FDungeonGenerateEditorModule; }; inline UDungeonMiniMapTextureLayer::UDungeonMiniMapTextureLayer(const FObjectInitializer& initializer) diff --git a/Source/DungeonGeneratorEditor/DungeonGeneratorEditor.Build.cs b/Source/DungeonGeneratorEditor/DungeonGeneratorEditor.Build.cs index 128d61f..4328402 100644 --- a/Source/DungeonGeneratorEditor/DungeonGeneratorEditor.Build.cs +++ b/Source/DungeonGeneratorEditor/DungeonGeneratorEditor.Build.cs @@ -33,8 +33,9 @@ public DungeonGeneratorEditor(ReadOnlyTargetRules Target) : base(Target) "Engine", "Slate", "SlateCore", - "PropertyEditor", - "DungeonGenerator", + "DesktopWidgets", + "PropertyEditor", + "DungeonGenerator", } ); BuildVersion Version; diff --git a/Source/DungeonGeneratorEditor/Private/DungeonGeneratorEditorModule.cpp b/Source/DungeonGeneratorEditor/Private/DungeonGeneratorEditorModule.cpp index 6e1bf70..4fba7aa 100644 --- a/Source/DungeonGeneratorEditor/Private/DungeonGeneratorEditorModule.cpp +++ b/Source/DungeonGeneratorEditor/Private/DungeonGeneratorEditorModule.cpp @@ -11,12 +11,21 @@ All Rights Reserved. #include "DungeonRoomAssetTypeActions.h" #include "BuildInfomation.h" #include "../../DungeonGenerator/Public/DungeonGenerateParameter.h" -#include "../../DungeonGenerator/Public/DungeonGenerator.h" +#include "../../DungeonGenerator/Public/DungeonGeneratorCore.h" +#include "../../DungeonGenerator/Public/DungeonMiniMapTexture.h" +#include "../../DungeonGenerator/Public/dungeonMiniMapTextureLayer.h" #include #include #include +#include #include +#include #include +#include +#include +#include +#include +#include static const FName DungeonGeneratorTabName("DungeonGenerator"); @@ -152,6 +161,82 @@ TSharedRef FDungeonGenerateEditorModule::OnSpawnPluginTab(const FSpawn ] + // Texture output size + + SVerticalBox::Slot() + .VAlign(VAlign_Center) + .FillHeight(1.f) + .Padding(2.f) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .VAlign(VAlign_Center) + .AutoWidth() + .Padding(2.f) + [ + SNew(STextBlock) + .Text(LOCTEXT("TextureOutputSizeLabel", "Texture output size")) + ] + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SNumericEntryBox) + .AllowSpin(true) + .MinValue(1) + .MinSliderValue(1) + .Value(512) + .Value_Raw(this, &FDungeonGenerateEditorModule::OnGetGenerateTextureSize) + .OnValueChanged_Raw(this, &FDungeonGenerateEditorModule::OnSetGenerateTextureSize) + ] + ] + + + SVerticalBox::Slot() + .VAlign(VAlign_Center) + .FillHeight(1.f) + .Padding(2.f) + [ + SNew(SButton) + .Text(LOCTEXT("GenerateTextureSizeButton", "Generate texture with size")) + .OnClicked_Raw(this, &FDungeonGenerateEditorModule::OnClickedGenerateTextureWithSizeButton) + ] + + // Texture output scale + + SVerticalBox::Slot() + .VAlign(VAlign_Center) + .FillHeight(1.f) + .Padding(2.f) + [ + SNew(SHorizontalBox) + + SHorizontalBox::Slot() + .VAlign(VAlign_Center) + .AutoWidth() + .Padding(2.f) + [ + SNew(STextBlock) + .Text(LOCTEXT("TextureOutputScaleLabel", "Texture output scale")) + ] + + SHorizontalBox::Slot() + .AutoWidth() + [ + SNew(SNumericEntryBox) + .AllowSpin(true) + .MinValue(1) + .MinSliderValue(1) + .Value(1) + .Value_Raw(this, &FDungeonGenerateEditorModule::OnGetGenerateTextureScale) + .OnValueChanged_Raw(this, &FDungeonGenerateEditorModule::OnSetGenerateTextureScale) + ] + ] + + + SVerticalBox::Slot() + .VAlign(VAlign_Center) + .FillHeight(1.f) + .Padding(2.f) + [ + SNew(SButton) + .Text(LOCTEXT("GenerateTextureScaleButton", "Generate texture with scale")) + .OnClicked_Raw(this, &FDungeonGenerateEditorModule::OnClickedGenerateTextureWithScaleButton) + ] + +SVerticalBox::Slot() .VAlign(VAlign_Center) @@ -209,28 +294,52 @@ void FDungeonGenerateEditorModule::RegisterMenus() } } +FString FDungeonGenerateEditorModule::GetObjectPath() const +{ + UDungeonGenerateParameter* dungeonGenerateParameter = mDungeonGenerateParameter.Get(); + return dungeonGenerateParameter ? dungeonGenerateParameter->GetPathName() : FString(""); +} + +void FDungeonGenerateEditorModule::SetAssetData(const FAssetData& assetData) +{ + mDungeonGenerateParameter = Cast(assetData.GetAsset()); +} + FReply FDungeonGenerateEditorModule::OnClickedGenerateButton() { + UWorld* world = GetWorldFromGameViewport(); + if (!IsValid(world)) + { + // TODO:エラーログを出力してください + return FReply::Unhandled(); + } + // 生成した全アクターを削除 - UDungeonGenerator::DestroySpawnedActors(UDungeonGenerator::GetWorldFromGameViewport()); + CDungeonGeneratorCore::DestroySpawnedActors(world); // アクターを生成 if (UDungeonGenerateParameter* dungeonGenerateParameter = mDungeonGenerateParameter.Get()) { - UDungeonGenerator* dungeonGenerator = NewObject(); - dungeonGenerator->Create(dungeonGenerateParameter); + mDungeonGeneratorCore = std::make_shared(world); + if (mDungeonGeneratorCore == nullptr) + { + // TODO:エラーログを出力してください + return FReply::Unhandled(); + } + + mDungeonGeneratorCore->Create(dungeonGenerateParameter); + mDungeonGeneratorCore->MovePlayerStart(); const int32 value = dungeonGenerateParameter->GetGeneratedRandomSeed(); mRandomSeedValue->SetText(FText::FromString(FString::FromInt(value))); - dungeonGenerator->MovePlayerStart(); - // TODO:ミニマップテクスチャの出力を検討して下さい return FReply::Handled(); } else { + // TODO:エラーログを出力してください return FReply::Unhandled(); } } @@ -238,19 +347,175 @@ FReply FDungeonGenerateEditorModule::OnClickedGenerateButton() FReply FDungeonGenerateEditorModule::OnClickedClearButton() { // 生成した全アクターを削除 - UDungeonGenerator::DestroySpawnedActors(UDungeonGenerator::GetWorldFromGameViewport()); + CDungeonGeneratorCore::DestroySpawnedActors(GetWorldFromGameViewport()); + + mDungeonGeneratorCore.reset(); + return FReply::Handled(); } -FString FDungeonGenerateEditorModule::GetObjectPath() const +TOptional FDungeonGenerateEditorModule::OnGetGenerateTextureSize() const { - UDungeonGenerateParameter* dungeonGenerateParameter = mDungeonGenerateParameter.Get(); - return dungeonGenerateParameter ? dungeonGenerateParameter->GetPathName() : FString(""); + return mGenerateTextureSize; } -void FDungeonGenerateEditorModule::SetAssetData(const FAssetData& assetData) +void FDungeonGenerateEditorModule::OnSetGenerateTextureSize(int32 value) { - mDungeonGenerateParameter = Cast(assetData.GetAsset()); + mGenerateTextureSize = value; +} + +TOptional FDungeonGenerateEditorModule::OnGetGenerateTextureScale() const +{ + return mGenerateTextureScale; +} + +void FDungeonGenerateEditorModule::OnSetGenerateTextureScale(int32 value) +{ + mGenerateTextureScale = value; +} + +FReply FDungeonGenerateEditorModule::OnClickedGenerateTextureWithSizeButton() +{ + if (UDungeonGenerateParameter* dungeonGenerateParameter = mDungeonGenerateParameter.Get()) + { + if (mDungeonGeneratorCore == nullptr) + { + // TODO:エラーログを出力してください + return FReply::Unhandled(); + } + + UDungeonMiniMapTextureLayer* dungeonMiniMapTextureLayer = NewObject(); + if (!IsValid(dungeonMiniMapTextureLayer)) + { + return FReply::Unhandled(); + } + + if (dungeonMiniMapTextureLayer->GenerateMiniMapTextureWithSize(mDungeonGeneratorCore, mGenerateTextureSize, dungeonGenerateParameter->GetGridSize()) == false) + { + // TODO:エラーログを出力してください + return FReply::Unhandled(); + } + + return SaveTextures(dungeonMiniMapTextureLayer); + } + + return FReply::Unhandled(); +} + +FReply FDungeonGenerateEditorModule::OnClickedGenerateTextureWithScaleButton() +{ + if (UDungeonGenerateParameter* dungeonGenerateParameter = mDungeonGenerateParameter.Get()) + { + if (mDungeonGeneratorCore == nullptr) + { + // TODO:エラーログを出力してください + return FReply::Unhandled(); + } + + UDungeonMiniMapTextureLayer* dungeonMiniMapTextureLayer = NewObject(); + if (!IsValid(dungeonMiniMapTextureLayer)) + { + return FReply::Unhandled(); + } + + if (dungeonMiniMapTextureLayer->GenerateMiniMapTextureWithScale(mDungeonGeneratorCore, mGenerateTextureScale, dungeonGenerateParameter->GetGridSize()) == false) + { + // TODO:エラーログを出力してください + return FReply::Unhandled(); + } + + return SaveTextures(dungeonMiniMapTextureLayer); + } + + return FReply::Unhandled(); +} + +FReply FDungeonGenerateEditorModule::SaveTextures(const UDungeonMiniMapTextureLayer* dungeonMiniMapTextureLayer) const +{ + class Finalizer final + { + public: + explicit Finalizer(std::function function) : mFunction(function) {} + ~Finalizer() { mFunction(); } + private: + std::function mFunction; + }; + + const TCHAR* basePath = TEXT("/Game/ProceduralTextures/"); + const FString absoluteBasePath = FPaths::ProjectContentDir() + TEXT("/ProceduralTextures/"); + FPackageName::RegisterMountPoint(basePath, absoluteBasePath); + + Finalizer unmount([basePath, &absoluteBasePath]() + { + FPackageName::UnRegisterMountPoint(basePath, absoluteBasePath); + } + ); + + TArray packages; + + const int32 floorHeight = dungeonMiniMapTextureLayer->GetFloorHeight(); + for (int32 floor = 0; floor < floorHeight; ++floor) + { + const FString packageName = FString::Printf(TEXT("Floor%d"), floor); + const FString packagePath = basePath + packageName; + UPackage* package = CreatePackage(*packagePath); + if (!IsValid(package)) + { + // TODO:エラーログを出力してください + return FReply::Unhandled(); + } + packages.Add(package); + + package->FullyLoad(); + package->MarkPackageDirty(); + + UDungeonMiniMapTexture* dungeonMiniMapTexture = dungeonMiniMapTextureLayer->GetByFloor(floor); + +#if UE_VERSION_NEWER_THAN(5, 1, 0) + FName textureName = MakeUniqueObjectName(package, UTexture2D::StaticClass(), FName(*packageName), EUniqueObjectNameOptions::GloballyUnique); +#else + FName textureName = MakeUniqueObjectName(package, UTexture2D::StaticClass(), FName(*packageName)); +#endif + UTexture2D* texture = DuplicateObject(dungeonMiniMapTexture->GetTexture(), package, textureName); + texture->SetFlags(RF_Public | RF_Standalone); + texture->ClearFlags(RF_Transient); + + FAssetRegistryModule::AssetCreated(texture); + + const FString longPackageName = FPackageName::LongPackageNameToFilename(packagePath, FPackageName::GetAssetPackageExtension()); + +#if UE_VERSION_OLDER_THAN(5, 0, 0) + const bool saved = UPackage::SavePackage(package, texture, RF_Public | RF_Standalone, *longPackageName); +#else + FSavePackageArgs saveArgs; + saveArgs.TopLevelFlags = RF_Public | RF_Standalone; + saveArgs.SaveFlags = SAVE_NoError; + const bool saved = UPackage::SavePackage(package, texture, *longPackageName, saveArgs); +#endif + if (saved == false) + { + // TODO:エラーログを出力してください + return FReply::Unhandled(); + } + } + + if (!PackageTools::UnloadPackages(packages)) + { + // TODO:エラーログを出力してください + return FReply::Unhandled(); + } + + packages.Empty(); + + return FReply::Handled(); +} + +UWorld* FDungeonGenerateEditorModule::GetWorldFromGameViewport() +{ + if (FWorldContext* worldContext = GEngine->GetWorldContextFromGameViewport(GEngine->GameViewport)) + return worldContext->World(); + + return nullptr; } #undef LOCTEXT_NAMESPACE diff --git a/Source/DungeonGeneratorEditor/Public/DungeonGenerateParameterTypeActions.h b/Source/DungeonGeneratorEditor/Public/DungeonGenerateParameterTypeActions.h index 48f42b5..9524ec3 100644 --- a/Source/DungeonGeneratorEditor/Public/DungeonGenerateParameterTypeActions.h +++ b/Source/DungeonGeneratorEditor/Public/DungeonGenerateParameterTypeActions.h @@ -8,7 +8,7 @@ All Rights Reserved. #include #include -class DUNGEONGENERATOREDITOR_API UDungeonGenerateParameterTypeActions : public FAssetTypeActions_Base +class UDungeonGenerateParameterTypeActions : public FAssetTypeActions_Base { public: UDungeonGenerateParameterTypeActions(EAssetTypeCategories::Type InAssetCategory); diff --git a/Source/DungeonGeneratorEditor/Public/DungeonGeneratorEditorModule.h b/Source/DungeonGeneratorEditor/Public/DungeonGeneratorEditorModule.h index 55d4312..a6ec32e 100644 --- a/Source/DungeonGeneratorEditor/Public/DungeonGeneratorEditorModule.h +++ b/Source/DungeonGeneratorEditor/Public/DungeonGeneratorEditorModule.h @@ -6,11 +6,14 @@ All Rights Reserved. #pragma once #include +#include // Forward declaration class FToolBarBuilder; class FMenuBuilder; +class CDungeonGeneratorCore; class UDungeonGenerateParameter; +class UDungeonMiniMapTextureLayer; class UStaticMesh; class FDungeonGenerateEditorModule : public IModuleInterface @@ -28,14 +31,31 @@ class FDungeonGenerateEditorModule : public IModuleInterface TSharedRef OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs); + FString GetObjectPath() const; + void SetAssetData(const FAssetData& assetData); + FReply OnClickedGenerateButton(); FReply OnClickedClearButton(); - FString GetObjectPath() const; - void SetAssetData(const FAssetData& assetData); + TOptional OnGetGenerateTextureSize() const; + void OnSetGenerateTextureSize(int32 value); + + TOptional OnGetGenerateTextureScale() const; + void OnSetGenerateTextureScale(int32 value); + + FReply OnClickedGenerateTextureWithSizeButton(); + FReply OnClickedGenerateTextureWithScaleButton(); + + FReply SaveTextures(const UDungeonMiniMapTextureLayer* dungeonMiniMapTextureLayer) const; + + static UWorld* GetWorldFromGameViewport(); private: + std::shared_ptr mDungeonGeneratorCore; + TSharedPtr PluginCommands; TSharedPtr mRandomSeedValue; TWeakObjectPtr mDungeonGenerateParameter = nullptr; + int32 mGenerateTextureSize = 512; + int32 mGenerateTextureScale = 1; }; diff --git a/Source/DungeonGeneratorEditor/Public/DungeonRoomAssetTypeActions.h b/Source/DungeonGeneratorEditor/Public/DungeonRoomAssetTypeActions.h index 217d3e0..63adffd 100644 --- a/Source/DungeonGeneratorEditor/Public/DungeonRoomAssetTypeActions.h +++ b/Source/DungeonGeneratorEditor/Public/DungeonRoomAssetTypeActions.h @@ -8,7 +8,7 @@ All Rights Reserved. #include #include -class DUNGEONGENERATOREDITOR_API FDungeonRoomAssetTypeActions : public FAssetTypeActions_Base +class FDungeonRoomAssetTypeActions : public FAssetTypeActions_Base { public: FDungeonRoomAssetTypeActions(EAssetTypeCategories::Type InAssetCategory);