资源随机生成初步接入

This commit is contained in:
2025-09-30 02:52:12 +08:00
parent 15a213a5c4
commit c39b910f83
29 changed files with 345 additions and 46 deletions

View File

@ -20,7 +20,7 @@ GameDefaultMap=/Game/Level/HomeLand.HomeLand
[/Script/Engine.RendererSettings]
r.Mobile.AntiAliasing=0
r.AntiAliasingMethod=3
r.AntiAliasingMethod=1
r.DefaultFeature.MotionBlur=False
[CoreRedirects]

Binary file not shown.

View File

@ -2,6 +2,15 @@ local Vector = import("Vector")
local GameplayStatics = import("GameplayStatics")
local BusyGameplayLibrary = import("BusyGameplayLibrary")
--[[****************************私有函数区域******************************]]--
--- 生成资源点
local function GenerateResourcePoint()
end
--- 保留到以后做联机内容时拓展
--- @class LevelGameMode
--- @field GameMapActorClass table

View File

@ -1 +0,0 @@
#include "Level/Map/ClimateLayerComponent.h"

View File

@ -0,0 +1 @@
#include "Level/Map/Components/ClimateLayerComponent.h"

View File

@ -0,0 +1 @@
#include "Level/Map/Components/CreatureLayerComponent.h"

View File

@ -0,0 +1 @@
#include "Level/Map/Components/DecorationLayerComponent.h"

View File

@ -0,0 +1 @@
#include "Level/Map/Components/LightingLayerComponent.h"

View File

@ -0,0 +1,138 @@
#include "Level/Map/Components/StaticResourceLayerComponent.h"
#include "Level/Map/GameMapActor.h"
#include "Level/Actor/BusyStaticResource.h"
#include "Utils/MitchellBestCandidate.h"
static FName GetOneOfAlwaysPresent(TMap<FName, int32>& AlwaysPresentResource)
{
TArray<FName> NeedRemoveKeys;
for (auto& Pair : AlwaysPresentResource)
{
if (Pair.Value <= 0)
{
NeedRemoveKeys.AddUnique(Pair.Key);
}
}
for (auto& RemovedKey : NeedRemoveKeys)
{
AlwaysPresentResource.Remove(RemovedKey);
}
if (AlwaysPresentResource.Num() == 0)
{
return FName();
}
auto &Pair = *AlwaysPresentResource.begin();
Pair.Value -= 1;
return Pair.Key;
}
inline static IGameMapInterface * GetMapActor(const UActorComponent* Component)
{
AActor *Owner = Component->GetOwner();
if (!Owner) return nullptr;
return Cast<IGameMapInterface>(Owner);
}
void UStaticResourceLayerComponent::GenerateResources()
{
TArray<FVector2D> ResourcePoints;
GenerateResourcePoints(ResourcePoints);
GenerateAlwaysPresentInfo(ResourcePoints);
AActor *Owner = GetOwner();
UWorld* World = GetWorld();
const IGameMapInterface* GameMap = Cast<IGameMapInterface>(Owner);
if(!Owner || !GameMap || !World) return;
const float MapFieldSize = GameMap->Execute_GetMapFieldSize(Owner);
for (int32 Index = 0; Index < GeneratedResourcePoints.Num(); Index++)
{
const TTuple<FName, FVector2D> &Info = GeneratedResourcePoints[Index];
const auto Config = GenerateConfig->FindRow<FStaticResourceGenerateConfig>(Info.Key, TEXT(""));
FActorSpawnParameters SpawnParameters;
SpawnParameters.Owner = Owner;
World->SpawnActor<ABusyStaticResource>(
Config->ResourceClass,
FVector(Info.Value.X * MapFieldSize, Info.Value.Y * MapFieldSize, 50.0f),
FRotator::ZeroRotator
);
}
}
void UStaticResourceLayerComponent::GenerateResourcePoints(TArray<FVector2D>& OutResourcePoint)
{
OutResourcePoint.Empty();
AActor *Owner = GetOwner();
if (!Owner) return;
const IGameMapInterface * MapInterface = Cast<IGameMapInterface>(Owner);
if (!MapInterface) return;
float MapWidth, MapHeight;
MapInterface->Execute_GetMapSize(Owner, MapWidth, MapHeight);
const UMitchellBestCandidate *PointCreator = NewObject<UMitchellBestCandidate>();
OutResourcePoint = PointCreator->GeneratePoints(ResourcePointCount, MapWidth, MapHeight);
}
void UStaticResourceLayerComponent::GetAlwaysPresentResourceList(TMap<FName, int32>& OutAlwaysPresentResource)const
{
OutAlwaysPresentResource.Empty();
if (!GenerateConfig) return;
for (const auto& Pair : GenerateConfig->GetRowMap())
{
const FStaticResourceGenerateConfig* RowData = reinterpret_cast<FStaticResourceGenerateConfig*>(Pair.Value);
if (RowData->MinGenerateCount > 0)
{
OutAlwaysPresentResource.Add(Pair.Key, RowData->MinGenerateCount);
}
}
}
bool UStaticResourceLayerComponent::GenerateAlwaysPresentInfo(TArray<FVector2D>& ResourcePoints)
{
AActor *Owner = GetOwner();
if (!Owner) return false;
const IGameMapInterface * MapInterface = Cast<IGameMapInterface>(Owner);
if (!MapInterface) return false;
TMap<FName, int> AlwaysPresentResource;
GetAlwaysPresentResourceList(AlwaysPresentResource);
for (int i = ResourcePoints.Num() - 1; i >= 0; i--) // 遍历所有的资源点尝试生成资源
{
FName CurrentSelected = GetOneOfAlwaysPresent(AlwaysPresentResource);
if (CurrentSelected.IsNone()) break; // 必须生成的资源已经全部生成了,则结束
const FVector2D& CurrentPoint = ResourcePoints[i];
FGameplayTag CurrentTerrain = MapInterface->Execute_GetTerrainAt(Owner, CurrentPoint.X, CurrentPoint.Y); // 获取这个资源点的地形类型
const auto Config = GenerateConfig->FindRow<FStaticResourceGenerateConfig>(
CurrentSelected, TEXT("")
);
if (!Config) continue;
if (Config->TerrainTypes.HasTag(CurrentTerrain)) // 资源的地形配置包含当前的地形,则添加进生成的列表
{
GeneratedResourcePoints.Add(TTuple<FName, FVector2D>(
CurrentSelected,
FVector2D(ResourcePoints[i].X, ResourcePoints[i].Y))
);
ResourcePoints[i].X = ResourcePoints[i].Y = -1;
}
}
if (!GetOneOfAlwaysPresent(AlwaysPresentResource).IsNone()) // 如果还有必须要生成的没有生成,则生成失败
{
GeneratedResourcePoints.Empty();
return false;
}
ResourcePoints.RemoveAll([](const FVector2D Element){ return Element.X < 0 && Element.Y < 0; });
return true;
}

View File

@ -1,4 +1,4 @@
#include "Level/Map/TerrainLayerComponent.h"
#include "Level/Map/Components/TerrainLayerComponent.h"
#include "Level/Generator/VoronoiTerrainGenerator.h"
#include "Paper2D/Classes/PaperTileLayer.h"
#include "Paper2D/Classes/PaperTileMapComponent.h"
@ -163,7 +163,6 @@ void UTerrainLayerComponent::BeginPlay()
TArray<int32> Priority;
TArray<FGameplayTag> TerrainData;
TArray<FGameplayTag> TerrainTypes;
TArray<bool> FilteredTerrainData;
for (auto TileSetConfig : TileSetConfigs)
{
TerrainTypes.Add(TileSetConfig.Key);
@ -172,18 +171,10 @@ void UTerrainLayerComponent::BeginPlay()
GenerateTerrain(TerrainTypes, Priority, MapWidth, TerrainData);
for (auto TerrainType : TerrainTypes)
{
FilteredTerrainData.Init(false, TerrainData.Num());
for (int32 i = 0; i < TerrainData.Num(); i++)
{
FilteredTerrainData[i] = (TerrainData[i] == TerrainType);
}
SetTerrainData(TerrainType, FilteredTerrainData);
}
SetTerrainData(TerrainData);
}
void UTerrainLayerComponent::SetTerrainData(const FGameplayTag& InTerrainType, const TArray<bool>& TerrainData)
void UTerrainLayerComponent::SetTerrainDataWithType(const FGameplayTag& InTerrainType, const TArray<bool>& InTerrainData)
{
// 将给定的数据绘制到TileMapLayer上
UPaperTileSet* TileSet = GetMapTileSet(InTerrainType, TileSetConfigs);
@ -193,7 +184,7 @@ void UTerrainLayerComponent::SetTerrainData(const FGameplayTag& InTerrainType, c
UE_LOG(LogTemp, Warning, TEXT("UTerrainLayerComponent::SetTerrainData"));
return;
}
if (TerrainData.Num() != MapWidth * MapHeight)
if (InTerrainData.Num() != MapWidth * MapHeight)
{
UE_LOG(LogTemp, Warning, TEXT("UTerrainLayerComponent::SetTerrainData"));
return;
@ -206,10 +197,10 @@ void UTerrainLayerComponent::SetTerrainData(const FGameplayTag& InTerrainType, c
const int32 CurRow = i * MapWidth;
const int32 NextRow = (i + 1) * MapWidth;
const int32 NeighborIndex = GetTileSetIndex(
TerrainData[CurRow + j],
TerrainData[CurRow + j + 1],
TerrainData[NextRow + j],
TerrainData[NextRow + j + 1]
InTerrainData[CurRow + j],
InTerrainData[CurRow + j + 1],
InTerrainData[NextRow + j],
InTerrainData[NextRow + j + 1]
);
TileInfo.TileSet = TileSet;
TileInfo.PackedTileIndex = DefaultNeighborDataToIdxMappings[NeighborIndex];
@ -218,6 +209,33 @@ void UTerrainLayerComponent::SetTerrainData(const FGameplayTag& InTerrainType, c
}
}
void UTerrainLayerComponent::SetTerrainData(const TArray<FGameplayTag>& InTerrainData)
{
TArray<int32> Priority;
TArray<bool> FilteredTerrainData;
for (auto &TileSetConfig : TileSetConfigs)
{
FilteredTerrainData.Init(false, InTerrainData.Num());
for (int32 i = 0; i < InTerrainData.Num(); i++)
{
FilteredTerrainData[i] = (InTerrainData[i] == TileSetConfig.Key);
}
SetTerrainDataWithType(TileSetConfig.Key, FilteredTerrainData);
}
TerrainLayerData = InTerrainData;
}
FGameplayTag UTerrainLayerComponent::GetTerrainAt(const int32 X, const int32 Y)
{
const int32 Index = X + Y * MapWidth;
if (TerrainLayerData.IsValidIndex(Index))
{
return TerrainLayerData[Index];
}
return FGameplayTag();
}
void UTerrainLayerComponent::SetupTerrainMeshes()
{
@ -246,9 +264,8 @@ void UTerrainLayerComponent::SetupTerrainMeshes()
NewTileMap->MapWidth = MapWidth;
NewTileMap->MapHeight = MapHeight;
NewTileMap->TileWidth = 128;
NewTileMap->TileHeight = 128;
NewTileMap->TileWidth = TileSetSize;
NewTileMap->TileHeight = TileSetSize;
UPaperTileLayer* NewLayer = NewObject<UPaperTileLayer>(NewTileMap);
NewLayer->LayerName = FText::FromString("TerrainLayer");

View File

@ -1 +0,0 @@
#include "Level/Map/CreatureLayerComponent.h"

View File

@ -1 +0,0 @@
#include "Level/Map/DecorationLayerComponent.h"

View File

@ -1,19 +1,35 @@
#include "Level/Map/GameMapActor.h"
#include "Level/Map/Components/StaticResourceLayerComponent.h"
AGameMapActor::AGameMapActor()
{
SceneComp = CreateDefaultSubobject<USceneComponent>(TEXT("SceneComp"));
TerrainLayer = CreateDefaultSubobject<UTerrainLayerComponent>(TEXT("TerrainLayer"));
ResourceLayer = CreateDefaultSubobject<UStaticResourceLayerComponent>(TEXT("ResourceLayer"));
this->RootComponent = SceneComp;
}
void AGameMapActor::GetMapSize_Implementation(float& OutWidth, float& OutHeight)
{
OutWidth = MapWidth;
OutHeight = MapHeight;
}
FGameplayTag AGameMapActor::GetTerrainAt_Implementation(const float X, const float Y)
{
return TerrainLayer->GetTerrainAt(X, Y);
}
float AGameMapActor::GetMapFieldSize_Implementation()
{
return MapFieldSize;
}
void AGameMapActor::BeginPlay()
{
Super::BeginPlay();
ResourceLayer->GenerateResources();
}
void AGameMapActor::EndPlay(const EEndPlayReason::Type EndPlayReason)

View File

@ -1 +0,0 @@
#include "Level/Map/LightingLayerComponent.h"

View File

@ -1 +0,0 @@
#include "Level/Map/PlacementLayerComponent.h"

View File

@ -1,4 +1,4 @@
#include "Level/Generator/MitchellBestCandidate.h"
#include "Utils/MitchellBestCandidate.h"
#include "Math/UnrealMathUtility.h"
UMitchellBestCandidate::UMitchellBestCandidate()

View File

@ -2,7 +2,7 @@
#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "Level/Generator/MitchellBestCandidate.h"
#include "Utils/MitchellBestCandidate.h"
#include "Level/Generator/VoronoiDiagram.h"
#include "Level/Generator/TerrainGeneratorBase.h"
#include "VoronoiTerrainGenerator.generated.h"

View File

@ -0,0 +1,63 @@
#pragma once
#include "Engine/DataTable.h"
#include "GameplayTagContainer.h"
#include "StaticResourceLayerComponent.generated.h"
USTRUCT(BlueprintType, Blueprintable)
struct FStaticResourceGenerateConfig: public FTableRowBase
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="备注")
FString Desc;
UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="生成的最少数量")
int MinGenerateCount = 0;
UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="生成权重")
int GenerateWeight = 1;
UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="可以在哪些地形生成")
FGameplayTagContainer TerrainTypes;
// 用于该资源生成时应该与某些资源保持多远的距离
UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="生成距离规则")
TMap<FName, float> GenerateDistanceLimit;
UPROPERTY(EditAnywhere, BlueprintReadOnly, DisplayName="需要生成的放置物类")
TSubclassOf<class ABusyStaticResource> ResourceClass;
};
UCLASS(Blueprintable, Blueprintable)
class UStaticResourceLayerComponent :public UActorComponent
{
GENERATED_BODY()
public:
void GenerateResources();
protected:
virtual void GenerateResourcePoints(TArray<FVector2D>& OutResourcePoint);
void GetAlwaysPresentResourceList(TMap<FName, int32>& OutAlwaysPresentResource)const;
bool GenerateAlwaysPresentInfo(TArray<FVector2D>& ResourcePoints);
public:
UPROPERTY(EditAnywhere)
TObjectPtr<UDataTable> GenerateConfig;
UPROPERTY(EditAnywhere)
int ResourcePointCount = 64;
TArray<TTuple<FName, FVector2D>> GeneratedResourcePoints;
protected:
};

View File

@ -44,23 +44,34 @@ public:
virtual void BeginPlay() override;
public:
void SetTerrainData(const FGameplayTag& InTerrainType, const TArray<bool> &TerrainData);
UFUNCTION(BlueprintCallable)
void SetTerrainData(const TArray<FGameplayTag>& InTerrainData);
UFUNCTION(BlueprintCallable)
FGameplayTag GetTerrainAt(const int32 X, const int32 Y);
protected:
void SetupTerrainMeshes();
void SetTerrainDataWithType(const FGameplayTag& InTerrainType, const TArray<bool> &InTerrainData);
protected:
UPROPERTY(EditAnywhere, BlueprintReadOnly)
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 MapWidth = 32;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 MapHeight = 32;
UPROPERTY(EditAnywhere, BlueprintReadWrite)
int32 TileSetSize = 128;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
TMap<FGameplayTag, TObjectPtr<UPaperTileSet>> TileSetConfigs;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
TMap<FGameplayTag, TObjectPtr<UPaperTileMapComponent>> TerrainMeshes;
UPROPERTY(BlueprintReadOnly)
TArray<FGameplayTag> TerrainLayerData;
};

View File

@ -1,25 +1,78 @@
#pragma once
#include "Level/Map/TerrainLayerComponent.h"
#include "Engine/DataTable.h"
#include "LuaActor.h"
#include "Level/Map/Components/TerrainLayerComponent.h"
#include "Level/Map/Components/StaticResourceLayerComponent.h"
#include "GameMapActor.generated.h"
UINTERFACE()
class UGameMapInterface : public UInterface
{
GENERATED_BODY()
};
class IGameMapInterface
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
void GetMapSize(float &OutX, float &OutY);
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
float GetMapFieldSize();
UFUNCTION(BlueprintCallable, BlueprintNativeEvent)
FGameplayTag GetTerrainAt(const float X, const float Y);
};
UCLASS(Blueprintable, Blueprintable)
class AGameMapActor : public AActor
class AGameMapActor : public ALuaActor, public IGameMapInterface
{
GENERATED_BODY()
public:
AGameMapActor();
public:
virtual void GetMapSize_Implementation(float& OutWidth, float& OutHeight) override;
virtual FGameplayTag GetTerrainAt_Implementation(const float X, const float Y) override;
virtual float GetMapFieldSize_Implementation() override;
public:
virtual void BeginPlay() override;
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
public:
UFUNCTION(BlueprintCallable)
const UTerrainLayerComponent* GetTerrainLayer() const
{
return TerrainLayer;
}
protected:
UPROPERTY(EditDefaultsOnly)
UPROPERTY(EditAnywhere, BlueprintReadOnly)
float MapWidth = 32;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
float MapHeight = 32;
UPROPERTY(EditAnywhere, BlueprintReadOnly)
float MapFieldSize = 128;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<UTerrainLayerComponent> TerrainLayer;
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TObjectPtr<class UStaticResourceLayerComponent> ResourceLayer;
UPROPERTY(EditDefaultsOnly, BlueprintReadWrite)
TObjectPtr<class USceneComponent> SceneComp;
};

View File

@ -1,7 +0,0 @@
#pragma once
class PlacementLayerComponent
{
public:
};