183 lines
7.0 KiB
C#
183 lines
7.0 KiB
C#
|
|
using System;
|
|||
|
|
using UnityEngine;
|
|||
|
|
|
|||
|
|
namespace Cielonos.MainGame
|
|||
|
|
{
|
|||
|
|
public partial class RunManager
|
|||
|
|
{
|
|||
|
|
/// <summary>
|
|||
|
|
/// 管理地图节点选择、进入和完成。
|
|||
|
|
/// 这里负责把 RunMapNode 转换为 RunPhase 与 Zone 加载请求,但不直接处理 CombatRoom 的敌人死亡事件。
|
|||
|
|
/// </summary>
|
|||
|
|
public class RunNodeFlowSubmodule : SubmoduleBase<RunManager>
|
|||
|
|
{
|
|||
|
|
public RunNodeFlowSubmodule(RunManager owner) : base(owner)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void SelectNode(Vector2Int targetPosition)
|
|||
|
|
{
|
|||
|
|
if (owner.currentRun == null)
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning("[RunManager] 当前没有进行中的 Run,忽略节点选择。");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!owner.CanSelectMapNodes)
|
|||
|
|
{
|
|||
|
|
LogMapSelectionBlocked();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (targetPosition == owner.currentRun.currentPosition)
|
|||
|
|
{
|
|||
|
|
Debug.Log("[RunManager] 目标即当前位置,忽略。");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!IsNodeReachable(targetPosition))
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning(
|
|||
|
|
$"[RunManager] 节点 {targetPosition} 不可到达" +
|
|||
|
|
"(不在已访问节点的1格范围内)。");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!owner.currentRun.mapData.nodes.TryGetValue(targetPosition, out RunMapNode targetNode))
|
|||
|
|
{
|
|||
|
|
Debug.LogError($"[RunManager] 节点 {targetPosition} 在地图数据中不存在。");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
owner.currentRun.currentPosition = targetPosition;
|
|||
|
|
bool isFirstVisit = owner.currentRun.visitedNodes.Add(targetPosition);
|
|||
|
|
bool isCompleted = owner.currentRun.completedNodes.Contains(targetPosition);
|
|||
|
|
|
|||
|
|
owner.RaiseNodeSelected(targetPosition);
|
|||
|
|
owner.RaiseZoneEntered(new ZoneEntryContext(targetPosition, targetNode, isFirstVisit, isCompleted));
|
|||
|
|
Debug.Log($"[RunManager] 移动到节点 {targetPosition},类型:{targetNode.nodeType}" +
|
|||
|
|
$",首次进入:{isFirstVisit},已完成:{isCompleted}");
|
|||
|
|
|
|||
|
|
CombatManager.AttackAreaSm.DestroyAll();
|
|||
|
|
EnterNode(targetNode);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public void CompleteCurrentNode()
|
|||
|
|
{
|
|||
|
|
if (owner.currentRun == null) return;
|
|||
|
|
|
|||
|
|
Vector2Int pos = owner.currentRun.currentPosition;
|
|||
|
|
if (owner.currentRun.completedNodes.Contains(pos))
|
|||
|
|
{
|
|||
|
|
Debug.Log($"[RunManager] 节点 {pos} 已完成过,跳过重复结算。但检查是否需要切回 MapSelection。");
|
|||
|
|
if (owner.currentPhase != RunPhase.MapSelection)
|
|||
|
|
{
|
|||
|
|
owner.phaseSm.TransitionToPhase(RunPhase.MapSelection);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!owner.currentRun.mapData.nodes.TryGetValue(pos, out RunMapNode node))
|
|||
|
|
{
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
owner.currentRun.completedNodes.Add(pos);
|
|||
|
|
|
|||
|
|
if (RunNodeTypeUtility.ShouldCountAsClearedRoom(node.nodeType))
|
|||
|
|
{
|
|||
|
|
owner.currentRun.roomsCleared++;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (RunNodeTypeUtility.IsSingleUseNode(node.nodeType))
|
|||
|
|
{
|
|||
|
|
owner.currentRun.exhaustedNodes.Add(pos);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
owner.RaiseNodeCompleted(node);
|
|||
|
|
|
|||
|
|
if (owner.currentRun.currentPosition == owner.currentRun.mapData.bossPosition)
|
|||
|
|
{
|
|||
|
|
owner.currentRun.isCompleted = true;
|
|||
|
|
Debug.Log("[RunManager] Boss 已击败,Run 通关!");
|
|||
|
|
owner.phaseSm.TransitionToPhase(RunPhase.Settlement);
|
|||
|
|
owner.RaiseRunEnded(owner.currentRun);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
owner.phaseSm.TransitionToPhase(RunPhase.MapSelection);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private bool IsNodeReachable(Vector2Int targetPosition)
|
|||
|
|
{
|
|||
|
|
if (owner.currentRun.visitedNodes.Contains(targetPosition))
|
|||
|
|
{
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
foreach (Vector2Int visitedPos in owner.currentRun.visitedNodes)
|
|||
|
|
{
|
|||
|
|
if (!owner.currentRun.mapData.nodes.TryGetValue(visitedPos, out RunMapNode node))
|
|||
|
|
{
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (node.connectedPositions.Contains(targetPosition))
|
|||
|
|
{
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void LogMapSelectionBlocked()
|
|||
|
|
{
|
|||
|
|
if (owner.currentRun == null)
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning("[RunManager] 当前没有进行中的 Run,忽略节点选择。");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!owner.phaseSm.IsPhaseAllowingNodeSelection())
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning($"[RunManager] 当前阶段为 {owner.currentPhase},不允许选择节点。");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (owner.HasPendingCombatRewards)
|
|||
|
|
{
|
|||
|
|
Debug.LogWarning($"[RunManager] 当前仍有 {owner.combatRewardSm.PendingCount} 个 Combat 奖励未领取,不能前往下一个节点。");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private void EnterNode(RunMapNode node)
|
|||
|
|
{
|
|||
|
|
bool isCompleted = owner.currentRun.completedNodes.Contains(owner.currentRun.currentPosition);
|
|||
|
|
RunPhase targetPhase = isCompleted ? RunPhase.MapSelection : RunNodeTypeUtility.ToRunPhase(node.nodeType);
|
|||
|
|
bool shouldStartBattleSetup = RunNodeTypeUtility.ShouldStartBattleSetup(node, isCompleted);
|
|||
|
|
ZoneSetupMode setupMode = shouldStartBattleSetup
|
|||
|
|
? ZoneSetupMode.CombatEncounter
|
|||
|
|
: ZoneSetupMode.EnvironmentOnly;
|
|||
|
|
|
|||
|
|
if (isCompleted)
|
|||
|
|
{
|
|||
|
|
Debug.Log($"[RunManager] 节点 {owner.currentRun.currentPosition} 已完成,跳过 {RunNodeTypeUtility.ToRunPhase(node.nodeType)},直接进入 MapSelection。");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (node.zoneData == null)
|
|||
|
|
{
|
|||
|
|
throw new Exception($"[RunManager] 节点 {owner.currentRun.currentPosition} 没有配置 ZoneData,无法进入对应阶段。");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
owner.phaseSm.TransitionToPhase(RunPhase.Transitioning);
|
|||
|
|
MapManager.Instance.LoadZone(node.zoneData, onComplete: () =>
|
|||
|
|
{
|
|||
|
|
owner.phaseSm.TransitionToPhase(targetPhase);
|
|||
|
|
}, setupMode: setupMode);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|