159 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			159 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "Level/Generator/TerrainGeneratorBase.h"
 | |
| 
 | |
| UTerrainGeneratorBase::UTerrainGeneratorBase()
 | |
| {
 | |
| }
 | |
| 
 | |
| int32 UTerrainGeneratorBase::AddTerrain(const FGameplayTag& TerrainTag)
 | |
| {
 | |
| 	FTerrainNodeInfo NewNode;
 | |
| 	NewNode.TerrainTag = TerrainTag;
 | |
| 	NewNode.Probability = 1.0f;
 | |
| 	NewNode.Weight = 1.0f;
 | |
| 	NewNode.ParentHandle = -1;
 | |
| 	NewNode.bIsLeafNode = true;
 | |
| 
 | |
| 	int32 Handle = NextHandle++;
 | |
| 	TerrainNodes.Add(Handle, NewNode);
 | |
| 	
 | |
| 	return Handle;
 | |
| }
 | |
| 
 | |
| void UTerrainGeneratorBase::SetWeight(int32 Handle, float Weight)
 | |
| {
 | |
| 	if (FTerrainNodeInfo* Node = TerrainNodes.Find(Handle))
 | |
| 	{
 | |
| 		Node->Weight = FMath::Max(0.0f, Weight);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void UTerrainGeneratorBase::SetProbability(int32 Handle, float Probability)
 | |
| {
 | |
| 	if (FTerrainNodeInfo* Node = TerrainNodes.Find(Handle))
 | |
| 	{
 | |
| 		Node->Probability = FMath::Clamp(Probability, 0.0f, 1.0f);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void UTerrainGeneratorBase::SetExclusive(const TArray<int32>& Handles){
 | |
| 	if (Handles.Num() <= 1) return;
 | |
| 	ExclusiveGroups.Add(TSet<int32>(Handles));
 | |
| }
 | |
| 
 | |
| void UTerrainGeneratorBase::BindChildTerrain(int32 ParentHandle, const TArray<int32>& ChildHandles)
 | |
| {
 | |
| 	if (FTerrainNodeInfo* ParentNode = TerrainNodes.Find(ParentHandle))
 | |
| 	{
 | |
| 		// 设置父节点为非叶子节点
 | |
| 		ParentNode->bIsLeafNode = false;
 | |
| 		
 | |
| 		// 添加子节点
 | |
| 		ParentNode->ChildHandles = ChildHandles;
 | |
| 		
 | |
| 		// 设置子节点的父节点
 | |
| 		for (int32 ChildHandle : ChildHandles)
 | |
| 		{
 | |
| 			if (FTerrainNodeInfo* ChildNode = TerrainNodes.Find(ChildHandle))
 | |
| 			{
 | |
| 				ChildNode->ParentHandle = ParentHandle;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| FGameplayTag UTerrainGeneratorBase::GetFinalTerrainTag(const int32 Handle) const{
 | |
| 	if (const FTerrainNodeInfo* Node = TerrainNodes.Find(Handle)){
 | |
| 		return Node->TerrainTag;
 | |
| 	}
 | |
| 	return FGameplayTag();
 | |
| }
 | |
| 
 | |
| TArray<int32> UTerrainGeneratorBase::GetValidLeafNodes() const
 | |
| {
 | |
| 	TSet<int32> ValidNodes;
 | |
| 	GetPreCheckVisibleHandles(ValidNodes);
 | |
| 	
 | |
| 	// 检查互斥关系, 待实现
 | |
| 	TSet<int32> FinalNodes;
 | |
| 	for (int32 Handle : ValidNodes){
 | |
| 		if (FinalNodes.Find(Handle)) continue;
 | |
| 		FinalNodes.Add(Handle);
 | |
| 	}
 | |
| 	
 | |
| 	// 只保留叶子节点
 | |
| 	TArray<int32> LeafNodes;
 | |
| 	for (int32 Handle : FinalNodes)
 | |
| 	{
 | |
| 		const FTerrainNodeInfo* Node = TerrainNodes.Find(Handle);
 | |
| 		if (Node && Node->bIsLeafNode)
 | |
| 		{
 | |
| 			LeafNodes.Add(Handle);
 | |
| 		}
 | |
| 	}
 | |
| 	
 | |
| 	return LeafNodes;
 | |
| }
 | |
| 
 | |
| 
 | |
| void UTerrainGeneratorBase::GetPreCheckVisibleHandles(TSet<int32>& VisibleHandles)const{
 | |
| 	bool bShouldAppear;
 | |
| 	TArray<bool> AppearanceCheckResult;
 | |
| 	const int TerrainNodeCount = TerrainNodes.Num();
 | |
| 	AppearanceCheckResult.Init(true, TerrainNodeCount);
 | |
| 
 | |
| 	for (const auto& Pair : TerrainNodes) {
 | |
| 		const int Handle = Pair.Key;
 | |
| 		const FTerrainNodeInfo* Node = &Pair.Value;
 | |
| 
 | |
| 		if (AppearanceCheckResult[Handle]) {
 | |
| 			bShouldAppear = FMath::FRand() < Node->Probability;
 | |
| 			AppearanceCheckResult[Handle] = bShouldAppear;
 | |
| 		}
 | |
| 		else {
 | |
| 			bShouldAppear = false;
 | |
| 		}
 | |
| 
 | |
| 		if (!bShouldAppear) {
 | |
| 			for (const int32 ChildHandle : Pair.Value.ChildHandles) {
 | |
| 				AppearanceCheckResult[ChildHandle] = false;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	for (int i = 0; i < TerrainNodeCount; ++i) {
 | |
| 		if (AppearanceCheckResult[i]) {
 | |
| 			VisibleHandles.Add(i);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| TArray<FGameplayTag> UTerrainGeneratorBase::GenerateMap(int32 Width, int32 Height)
 | |
| {
 | |
| 	TArray<FGameplayTag> Map;
 | |
| 	Map.SetNum(Width * Height);
 | |
| 
 | |
| 	// 获取有效的叶子节点
 | |
| 	TArray<int32> ValidLeafNodes = GetValidLeafNodes();
 | |
| 	
 | |
| 	if (ValidLeafNodes.Num() == 0)
 | |
| 	{
 | |
| 		UE_LOG(LogTemp, Error, TEXT("No valid terrain nodes to generate map!"));
 | |
| 		return Map;
 | |
| 	}
 | |
| 
 | |
| 	if (GenerateWithNodes(Map, Width, Height, ValidLeafNodes))
 | |
| 	{
 | |
| 		return Map;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		return TArray<FGameplayTag>();
 | |
| 	}
 | |
| }
 | |
| 
 | |
| bool UTerrainGeneratorBase::GenerateWithNodes(TArray<FGameplayTag>& Map, int32 Width, int32 Height, const TArray<int32>& ValidLeafNodes)
 | |
| {
 | |
| 	return false;
 | |
| }
 |