323 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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);
}
}
}