From c89243452d65081030313b43401a2128bc756ee6 Mon Sep 17 00:00:00 2001 From: wyatt Date: Tue, 21 Oct 2025 00:05:40 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=B5=84=E6=BA=90=E6=8E=92?= =?UTF-8?q?=E5=B8=83=E7=AE=97=E6=B3=95=20#1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 之前的实现有bug,现在营地基本一定能生成 现在还有一个问题是,森林非常小的情况下,在森林的资源点可能达不到必须生成的数量要求 需要进一步解决这个问题 --- .../StaticResourceLayerComponent.cpp | 101 +++++++++--------- .../Components/StaticResourceLayerComponent.h | 2 +- 2 files changed, 54 insertions(+), 49 deletions(-) diff --git a/Source/BusyRabbit/Private/Level/Map/Components/StaticResourceLayerComponent.cpp b/Source/BusyRabbit/Private/Level/Map/Components/StaticResourceLayerComponent.cpp index 28dc271..fa19967 100644 --- a/Source/BusyRabbit/Private/Level/Map/Components/StaticResourceLayerComponent.cpp +++ b/Source/BusyRabbit/Private/Level/Map/Components/StaticResourceLayerComponent.cpp @@ -3,46 +3,58 @@ #include "Level/Actor/BusyStaticResource.h" #include "Utils/MitchellBestCandidate.h" -static FName PeekOneOfAlwaysPresent(TMap& AlwaysPresentResource) + +static void CleanUpEmptyResources(TMap& AlwaysPresentResource) { - TArray NeedRemoveKeys; + TArray NeedRemoveList; for (auto& Pair : AlwaysPresentResource) { if (Pair.Value <= 0) { - NeedRemoveKeys.Add(Pair.Key); + NeedRemoveList.Add(Pair.Key); + continue; } } - for (auto& RemovedKey : NeedRemoveKeys) + for (FName& RemovedKey : NeedRemoveList) { AlwaysPresentResource.Remove(RemovedKey); } - - if (AlwaysPresentResource.Num() == 0) - { - return FName(); - } - const auto &Pair = *AlwaysPresentResource.begin(); - return Pair.Key; } - -static void ConsumeOneOfAlwaysPresent(TMap& AlwaysPresentResource, const FName &ResourceName) +/** + * 给定地形,遍历所有的资源,找一个能生成在这个地形上的资源 + * @param CurrentTerrain 指定地形 + * @param AlwaysPresentResource 必须要生成的资源清单 + * @param GenerateConfig 表格配置 + * @return 生成的资源的ID + */ +static FName TryGenerateResourceAtTerrain(const FGameplayTag &CurrentTerrain, TMap& AlwaysPresentResource, const UDataTable* GenerateConfig) { - if (const int32 *RemainCount = AlwaysPresentResource.Find(ResourceName)) + FName Selected; + for (auto& Pair : AlwaysPresentResource) { - if (*RemainCount > 0) + if (Pair.Value <= 0) continue; + + const auto Config = GenerateConfig->FindRow(Pair.Key, TEXT("")); + if (!Config) { - AlwaysPresentResource[ResourceName] = *RemainCount - 1; - return; + // TODO LOG + continue; + } + + if (Config->TerrainTypes.HasTag(CurrentTerrain)) + { + Pair.Value -= 1; + Selected = Pair.Key; + break; } } - UE_LOG(LogMapGenerate, Error, TEXT("ConsumeOneOfAlwaysPresent %s failed"), *ResourceName.ToString()); + CleanUpEmptyResources(AlwaysPresentResource); + return Selected; } - inline static IGameMapInterface * GetMapActor(const UActorComponent* Component) { AActor *Owner = Component->GetOwner(); @@ -54,12 +66,16 @@ inline static IGameMapInterface * GetMapActor(const UActorComponent* Component) void UStaticResourceLayerComponent::GenerateResources() { TArray ResourcePoints; + TMap AlwaysPresentResource; // 生成资源点 GenerateResourcePoints(ResourcePoints); + + // 获取所有要生成的资源 + GetAlwaysPresentResourceList(AlwaysPresentResource); // 生成必定生成的资源 - GenerateAlwaysPresentInfo(ResourcePoints); + GenerateAlwaysPresentInfo(ResourcePoints, AlwaysPresentResource); // 利用剩下的资源点,根据权重生成资源 GenerateResourceByWeight(ResourcePoints); @@ -104,6 +120,10 @@ void UStaticResourceLayerComponent::GenerateResourcePoints(TArray& Ou OutResourcePoint = PointCreator->GeneratePoints(ResourcePointCount, MapWidth, MapHeight); } +/** + * 获取所有要生成的资源列表 + * @param OutAlwaysPresentResource 资源名和资源数量的键值Map + */ void UStaticResourceLayerComponent::GetAlwaysPresentResourceList(TMap& OutAlwaysPresentResource)const { OutAlwaysPresentResource.Empty(); @@ -150,53 +170,38 @@ bool UStaticResourceLayerComponent::GetCanGenerateResourcesWeight(const FVector2 } -bool UStaticResourceLayerComponent::GenerateAlwaysPresentInfo(TArray& ResourcePoints) +bool UStaticResourceLayerComponent::GenerateAlwaysPresentInfo(TArray& ResourcePoints, TMap& AlwaysPresent) { AActor *Owner = GetOwner(); if (!Owner) return false; const IGameMapInterface * MapInterface = Cast(Owner); if (!MapInterface) return false; - TMap AlwaysPresentResource; - GetAlwaysPresentResourceList(AlwaysPresentResource); - for (int i = ResourcePoints.Num() - 1; i >= 0; i--) // 遍历所有的资源点尝试生成资源 { - FName CurrentSelected = PeekOneOfAlwaysPresent(AlwaysPresentResource); - if (CurrentSelected.IsNone()) // 必须生成的资源已经全部生成了,则结束 - { - UE_LOG(LogMapGenerate, Log, TEXT("UStaticResourceLayerComponent::GenerateAlwaysPresentInfo All Always present created.")) - break; - } - + // 取资源点 const FVector2D& CurrentPoint = ResourcePoints[i]; - FGameplayTag CurrentTerrain = MapInterface->Execute_GetTerrainAt(Owner, CurrentPoint.X, CurrentPoint.Y); // 获取这个资源点的地形类型 - const auto Config = GenerateConfig->FindRow( - CurrentSelected, TEXT("") - ); - if (!Config) continue; + + // 获取这个资源点的地形类型 + FGameplayTag CurrentTerrain = MapInterface->Execute_GetTerrainAt(Owner, CurrentPoint.X, CurrentPoint.Y); - if (Config->TerrainTypes.HasTag(CurrentTerrain)) // 资源的地形配置包含当前的地形,则添加进生成的列表 + // 获取要生成的资源名 + FName&& ResourceName = TryGenerateResourceAtTerrain(CurrentTerrain, AlwaysPresent, GenerateConfig); + + if (!ResourceName.IsNone()) { - TryPushGenerateResult(CurrentSelected, CurrentPoint); - // GeneratedResourcePoints.Add(TTuple(CurrentSelected, FVector2D(ResourcePoints[i].X, ResourcePoints[i].Y))); - ConsumeOneOfAlwaysPresent(AlwaysPresentResource, CurrentSelected); + TryPushGenerateResult(ResourceName, CurrentPoint); ResourcePoints[i].X = ResourcePoints[i].Y = -1; UE_LOG(LogMapGenerate, Log, TEXT("UStaticResourceLayerComponent::GenerateAlwaysPresentInfo Create %s at (%d, %d)"), - *CurrentSelected.ToString(), int32(ResourcePoints[i].X), int32(ResourcePoints[i].Y)) + *ResourceName.ToString(), int32(ResourcePoints[i].X), int32(ResourcePoints[i].Y)) } else { UE_LOG(LogMapGenerate, Log, TEXT("UStaticResourceLayerComponent::GenerateAlwaysPresentInfo Failed create %s at (%d,%d) in %s"), - *CurrentSelected.ToString(), int32(ResourcePoints[i].X), int32(ResourcePoints[i].Y), *CurrentTerrain.ToString()); + *ResourceName.ToString(), int32(ResourcePoints[i].X), int32(ResourcePoints[i].Y), *CurrentTerrain.ToString()); } } - - if (!PeekOneOfAlwaysPresent(AlwaysPresentResource).IsNone()) // 如果还有必须要生成的没有生成,则生成失败 - { - GeneratedResourcePoints.Empty(); - return false; - } + // 清理已经生成的数据 ResourcePoints.RemoveAll([](const FVector2D Element){ return Element.X < 0 && Element.Y < 0; }); return true; } diff --git a/Source/BusyRabbit/Public/Level/Map/Components/StaticResourceLayerComponent.h b/Source/BusyRabbit/Public/Level/Map/Components/StaticResourceLayerComponent.h index c062823..2776b7c 100644 --- a/Source/BusyRabbit/Public/Level/Map/Components/StaticResourceLayerComponent.h +++ b/Source/BusyRabbit/Public/Level/Map/Components/StaticResourceLayerComponent.h @@ -60,7 +60,7 @@ protected: virtual void GenerateResourcePoints(TArray& OutResourcePoint); - bool GenerateAlwaysPresentInfo(TArray& ResourcePoints); + bool GenerateAlwaysPresentInfo(TArray& ResourcePoints, TMap& AlwaysPresent); void GenerateResourceByWeight(TArray& ResourcePoints);