323 lines
11 KiB
C++
323 lines
11 KiB
C++
#include "FishingMapSubSystem.h"
|
||
|
||
#include "FishingRodConfigSubsystem.h"
|
||
#include "Engine/Engine.h"
|
||
#include "Kismet/GameplayStatics.h"
|
||
#include "ProjectFish/DataAsset/MapConfigAsset.h"
|
||
|
||
UFishingMapNode::UFishingMapNode()
|
||
{
|
||
NodeID = FGuid::NewGuid();
|
||
|
||
NodeType = EMapNodeType::Battle;
|
||
LayerIndex = 0;
|
||
IndexInLayer = 0;
|
||
Position = FVector2D::ZeroVector;
|
||
}
|
||
|
||
void UFishingMapNode::RandomNodeType()
|
||
{
|
||
NodeType = static_cast<EMapNodeType>(FMath::RandRange(0, 1));
|
||
}
|
||
|
||
UFishingMapSubSystem::UFishingMapSubSystem()
|
||
{
|
||
|
||
}
|
||
|
||
void UFishingMapSubSystem::GenerateMap()
|
||
{
|
||
GenerateMapWithConfig(MapConfig);
|
||
}
|
||
|
||
void UFishingMapSubSystem::GenerateMapWithConfig(const UMapConfigAsset* Config)
|
||
{
|
||
// 清空现有数据
|
||
ClearMap();
|
||
|
||
// 生成节点
|
||
GenerateNodes();
|
||
|
||
// 计算节点位置
|
||
CalculateNodePositions();
|
||
|
||
// 生成连线
|
||
GenerateConnections();
|
||
|
||
UE_LOG(LogTemp, Log, TEXT("地图生成完成:%d层,共%d个节点,%d条连线"),
|
||
GetLayerCount(), AllNodes.Num(), AllConnections.Num());
|
||
}
|
||
|
||
int32 UFishingMapSubSystem::GetNodeAtLayerIndex(FGuid NodeID) const
|
||
{
|
||
for (FMapLayer Layer: AllLayers)
|
||
{
|
||
for (int i = 0; i < Layer.GetNodeNum(); i++)
|
||
{
|
||
if ( Layer.GetNode(i)->NodeID == NodeID)
|
||
return i;
|
||
}
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
UFishingMapNode* UFishingMapSubSystem::GetNode(FGuid NodeID)
|
||
{
|
||
for (auto node: AllNodes)
|
||
{
|
||
if (node->NodeID == NodeID)
|
||
return node;
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
void UFishingMapSubSystem::ClearMap()
|
||
{
|
||
AllNodes.Empty();
|
||
AllConnections.Empty();
|
||
AllLayers.Empty();
|
||
}
|
||
|
||
void UFishingMapSubSystem::MoveToNode(FGuid NodeID)
|
||
{
|
||
PlayerPosNodeID = NodeID;
|
||
TArray<FGuid> MoveableNodeIDs;
|
||
GetAllConnectedNodes(NodeID, MoveableNodeIDs);
|
||
for (auto node:AllNodes)
|
||
{
|
||
if (MoveableNodeIDs.Find(node->NodeID) == -1)
|
||
{
|
||
//节点不在可移动的列表内,更新状态
|
||
OnNodeStateChange.Broadcast(node->NodeID, EMapNodeState::Immovable);
|
||
}
|
||
else
|
||
{
|
||
OnNodeStateChange.Broadcast(node->NodeID, EMapNodeState::Moveable);
|
||
}
|
||
}
|
||
//根据节点类型 触发不同的事件
|
||
UFishingMapNode* node = GetNode(NodeID);
|
||
switch (node->NodeType)
|
||
{
|
||
case EMapNodeType::Battle:
|
||
UGameplayStatics::OpenLevel(this, MapConfig->BattleMapName);
|
||
break;
|
||
case EMapNodeType::Boss:
|
||
UGameplayStatics::OpenLevel(this, MapConfig->BattleMapName);
|
||
break;
|
||
case EMapNodeType::Skill:
|
||
//添加技能到背包系统中
|
||
if (UGameInstance* GameInstance = GetGameInstance())
|
||
{
|
||
|
||
//USkillAsset* RandomSkill =LoadObject<USkillAsset>(this, * MapConfig->RandomSkills[FMath::RandRange(0, MapConfig->RandomSkills.Num() - 1)].ToString());
|
||
USkillAsset* RandomSkill = DuplicateObject<USkillAsset>(MapConfig->RandomSkills[FMath::RandRange(0, MapConfig->RandomSkills.Num() - 1)], this);
|
||
if (!GameInstance->GetSubsystem<UFishingRodConfigSubsystem>()->AddSkillToPlayerInventory(RandomSkill))
|
||
{
|
||
UE_LOG(LogTemp, Error, TEXT("道具节点添加道具失败,背包没有多余位置"));
|
||
}
|
||
}
|
||
break;;
|
||
}
|
||
}
|
||
|
||
bool UFishingMapSubSystem::MoveToAble(FGuid TargetNodeID)
|
||
{
|
||
UFishingMapNode* currentNode = GetNode(PlayerPosNodeID);
|
||
UFishingMapNode* targetNode = GetNode(TargetNodeID);
|
||
if (currentNode)
|
||
{
|
||
for (auto connection: AllConnections)
|
||
{
|
||
if (connection.FromNodeID == PlayerPosNodeID && connection.ToNodeID == TargetNodeID)
|
||
{
|
||
return true;;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return targetNode->NodeState == EMapNodeState::Moveable;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
|
||
void UFishingMapSubSystem::GenerateNodes()
|
||
{
|
||
AllLayers.SetNum(MapConfig->TotalLayers);
|
||
UE_LOG(LogTemp, Warning, TEXT("生成layer层数: %d "), MapConfig->TotalLayers );
|
||
for (int32 LayerIndex = 0; LayerIndex < MapConfig->TotalLayers ; ++LayerIndex)
|
||
{
|
||
if (LayerIndex == MapConfig->TotalLayers - 1)
|
||
{
|
||
//最后一层 只有一个Boss
|
||
UFishingMapNode* NewNode = NewObject<UFishingMapNode>(this);
|
||
NewNode->LayerIndex = LayerIndex;
|
||
NewNode->IndexInLayer = 0;
|
||
NewNode->NodeType = EMapNodeType::Boss;
|
||
NewNode->NodeState = EMapNodeState::Immovable;
|
||
AllNodes.Add(NewNode);
|
||
AllLayers[LayerIndex].AddNode(NewNode);
|
||
}
|
||
else
|
||
{
|
||
// 随机生成节点数量
|
||
int32 NodeCount = FMath::RandRange(MapConfig->Layer_MinNodes, MapConfig->Layer_MaxNodes);
|
||
//int32 NodeCount = 4;
|
||
// 生成节点
|
||
for (int32 NodeIndex = 0; NodeIndex < NodeCount; ++NodeIndex)
|
||
{
|
||
UFishingMapNode* NewNode = NewObject<UFishingMapNode>(this);
|
||
NewNode->LayerIndex = LayerIndex;
|
||
NewNode->IndexInLayer = NodeIndex;
|
||
//只有第一层的节点 默认是可用状态
|
||
if (LayerIndex == 0)
|
||
{
|
||
NewNode->NodeState = EMapNodeState::Moveable;
|
||
}
|
||
else
|
||
{
|
||
NewNode->NodeState = EMapNodeState::Immovable;
|
||
}
|
||
// 随机节点类型
|
||
NewNode->RandomNodeType();
|
||
AllNodes.Add(NewNode);
|
||
AllLayers[LayerIndex].AddNode(NewNode);
|
||
}
|
||
}
|
||
UE_LOG(LogTemp, Warning, TEXT("layer:%d node: %d "), LayerIndex, AllLayers[LayerIndex].GetNodeNum() );
|
||
}
|
||
}
|
||
|
||
void UFishingMapSubSystem::CalculateNodePositions()
|
||
{
|
||
for (int32 LayerIndex = 0; LayerIndex < AllLayers.Num(); ++LayerIndex)
|
||
{
|
||
|
||
FMapLayer& Layer= AllLayers[LayerIndex];
|
||
int32 NodeCount = Layer.GetNodeNum();
|
||
float TotalWidth = (NodeCount - 1) * (MapConfig->NodeOffsetX); //水平总距离
|
||
float Y = LayerIndex * MapConfig->NodeOffsetY; //垂直高度
|
||
|
||
float StartX = -TotalWidth * 0.5f;
|
||
|
||
for (int32 NodeIndex = 0; NodeIndex <NodeCount; ++NodeIndex)
|
||
{
|
||
float X = StartX + NodeIndex * MapConfig->NodeOffsetX;
|
||
Layer.GetNode(NodeIndex)->Position = FVector2D(X, Y);
|
||
}
|
||
}
|
||
}
|
||
|
||
void UFishingMapSubSystem::GenerateConnections()
|
||
{
|
||
AllConnections.Empty();
|
||
|
||
// 为每对相邻层生成连线
|
||
for (int32 LayerIndex = 0; LayerIndex < AllLayers.Num() - 1; ++LayerIndex)
|
||
{
|
||
TArray<FSimpleConnection> LayerConnections = GenerateNonCrossingConnections(LayerIndex, LayerIndex + 1);
|
||
AllConnections.Append(LayerConnections);
|
||
}
|
||
|
||
// 更新节点的连接信息
|
||
for (const FSimpleConnection& Connection : AllConnections)
|
||
{
|
||
// 找到起始节点并添加连接
|
||
for (UFishingMapNode* Node : AllNodes)
|
||
{
|
||
if (Node && Node->NodeID == Connection.FromNodeID)
|
||
{
|
||
Node->ConnectedNodes.AddUnique(Connection.ToNodeID);
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
TArray<FSimpleConnection> UFishingMapSubSystem::GenerateNonCrossingConnections(int32 FromLayer, int32 ToLayer)
|
||
{
|
||
TArray<FSimpleConnection> Connections;
|
||
|
||
UE_LOG(LogTemp, Warning, TEXT("生成层级 %d -> %d 的随机连接"),FromLayer, ToLayer);
|
||
if (FromLayer == AllLayers.Num() - 2)
|
||
{
|
||
//倒数第二行,所有都连接到最终boss房间
|
||
UE_LOG(LogTemp, Warning, TEXT("生成boss节点的连接"));
|
||
FMapLayer FromNodes = AllLayers[FromLayer];
|
||
FGuid BossID = AllLayers[ToLayer].GetNode(0)->NodeID;
|
||
for (int32 NodeIndex = 0; NodeIndex < FromNodes.GetNodeNum(); ++NodeIndex)
|
||
{
|
||
Connections.Add(FSimpleConnection(FromNodes.GetNode(NodeIndex)->NodeID, BossID));
|
||
UE_LOG(LogTemp, Warning, TEXT("下层 %d -> 上层 %d "),GetNodeAtLayerIndex(FromNodes.GetNode(NodeIndex)->NodeID),
|
||
GetNodeAtLayerIndex(BossID));
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//第一步 随机为每个fromnode 分配指定范围的上层节点
|
||
UE_LOG(LogTemp, Warning, TEXT("第一轮生成节点的连接"));
|
||
FMapLayer FromNodes = AllLayers[FromLayer];
|
||
FMapLayer ToNodes = AllLayers[ToLayer];
|
||
int32 LastToNodeIndex = 0;
|
||
for (int32 NodeIndex = 0; NodeIndex < FromNodes.GetNodeNum(); ++NodeIndex)
|
||
{
|
||
int32 connectionBeginIndex = LastToNodeIndex;
|
||
int32 endIndex = ToNodes.GetNodeNum() - 1;
|
||
//随机连线的最左侧位置,根据当前所在layer的index 调整概率
|
||
// int32 connectionEndIndex = FMath::Max(connectionBeginIndex,
|
||
// (FMath::RandRange(connectionBeginIndex, endIndex + (FromNodes.GetNodeNum() - NodeIndex)) - (FromNodes.GetNodeNum() - NodeIndex)) );
|
||
int32 connectionEndIndex = FMath::RandRange(connectionBeginIndex, endIndex);
|
||
//随机指定当前node 连接上层node的范围
|
||
LastToNodeIndex = connectionEndIndex;
|
||
for(int32 i = connectionBeginIndex; i <= connectionEndIndex; ++i)
|
||
{
|
||
//添加连线
|
||
Connections.Add(FSimpleConnection(FromNodes.GetNode(NodeIndex)->NodeID, ToNodes.GetNode(i )->NodeID));
|
||
|
||
UE_LOG(LogTemp, Warning, TEXT("下层 %d -> 上层 %d "),GetNodeAtLayerIndex(FromNodes.GetNode(NodeIndex)->NodeID),
|
||
GetNodeAtLayerIndex(ToNodes.GetNode(i )->NodeID));
|
||
}
|
||
}
|
||
//第二步 确保tolayer 每个节点都有连接线,没有连接线的分配 指定范围内的下层节点
|
||
if(LastToNodeIndex != ToNodes.GetNodeNum() - 1)
|
||
{
|
||
UE_LOG(LogTemp, Warning, TEXT("第二轮生成节点的连接"));
|
||
//还有上层节点是没有被连线状态,都连接到下层的最后一个节点
|
||
for(int32 ToNodeIndex = LastToNodeIndex; ToNodeIndex < ToNodes.GetNodeNum(); ++ToNodeIndex)
|
||
{
|
||
Connections.Add(FSimpleConnection(FromNodes.GetNode(FromNodes.GetNodeNum() - 1)->NodeID, ToNodes.GetNode(ToNodeIndex)->NodeID));
|
||
UE_LOG(LogTemp, Warning, TEXT("下层 %d -> 上层 %d "),GetNodeAtLayerIndex(FromNodes.GetNode(FromNodes.GetNodeNum() - 1)->NodeID),
|
||
GetNodeAtLayerIndex(ToNodes.GetNode(ToNodeIndex)->NodeID));
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
// for(auto connection: Connections)
|
||
// {
|
||
// UE_LOG(LogTemp, Warning, TEXT("下层 %d -> 上层 %d "),GetNodeAtLayerIndex(connection.FromNodeID),
|
||
// GetNodeAtLayerIndex(connection.ToNodeID));
|
||
// }
|
||
|
||
|
||
return Connections;
|
||
}
|
||
|
||
void UFishingMapSubSystem::GetAllConnectedNodes(FGuid NodeID, TArray<FGuid>& ConnectedNodes)
|
||
{
|
||
//获取所有可移动的节点
|
||
ConnectedNodes.Add(NodeID);
|
||
if (GetNode(NodeID)->ConnectedNodes.Num() != 0)
|
||
{
|
||
ConnectedNodes.Append(GetNode(NodeID)->ConnectedNodes);
|
||
for (auto ConnectedNode : GetNode(NodeID)->ConnectedNodes)
|
||
{
|
||
GetAllConnectedNodes(ConnectedNode, ConnectedNodes);
|
||
}
|
||
}
|
||
|
||
|
||
} |