RunNode 接入游戏主流程

- NodeMapForm:节点地图
    - NodeItem:节点入口
This commit is contained in:
SepComet
2026-03-08 11:27:51 +08:00
parent c81bf97903
commit 5c6f9bf3a4
94 changed files with 6145 additions and 651 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d17e5e91c45a8814c954edf31b063100
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -86,7 +86,7 @@ namespace GeometryTD.Procedure
ChangeState<ProcedureMenu>(procedureOwner);
break;
case SceneType.Main:
ChangeState<ProcedureTest>(procedureOwner);
ChangeState<ProcedureMain>(procedureOwner);
break;
default:
Log.Debug($"Scene {sceneType.ToString()} don't configure a procedure");
@@ -146,4 +146,4 @@ namespace GeometryTD.Procedure
ne.DependencyAssetName, ne.LoadedCount.ToString(), ne.TotalCount.ToString());
}
}
}
}
@@ -0,0 +1,213 @@
using GameFramework.Event;
using GameFramework.Fsm;
using GameFramework.Procedure;
using GeometryTD.CustomEvent;
using GeometryTD.Definition;
using GeometryTD.UI;
using UnityGameFramework.Runtime;
namespace GeometryTD.Procedure
{
public class ProcedureMain : ProcedureBase
{
public override bool UseNativeDialog => false;
private RepoFormUseCase _repoFormUseCase;
private NodeMapFormUseCase _nodeMapFormUseCase;
private RunState _currentRunState;
#region FSM
protected override void OnEnter(IFsm<IProcedureManager> procedureOwner)
{
base.OnEnter(procedureOwner);
GameEntry.Event.Subscribe(CombatFailureReturnEventArgs.EventId, OnCombatFailureReturn);
GameEntry.Event.Subscribe(NodeCompleteEventArgs.EventId, OnNodeComplete);
GameEntry.Event.Subscribe(NodeEnterEventArgs.EventId, OnNodeEnter);
GameEntry.Event.Subscribe(NodeMapNodeEnterRequestedEventArgs.EventId, OnNodeMapNodeEnterRequested);
GameEntry.EventNode.OnInit();
GameEntry.CombatNode.OnInit(LevelThemeType.Plain);
GameEntry.ShopNode.OnInit();
GameEntry.PlayerInventory?.OnInit();
_currentRunState = RunStateFactory.CreateFixedRun(
LevelThemeType.Plain,
GameEntry.PlayerInventory != null
? GameEntry.PlayerInventory.GetInventorySnapshot()
: null);
_repoFormUseCase = new RepoFormUseCase();
GameEntry.UIRouter.BindUIUseCase(UIFormType.RepoForm, _repoFormUseCase);
_nodeMapFormUseCase = new NodeMapFormUseCase();
_nodeMapFormUseCase.SetRunState(_currentRunState);
GameEntry.UIRouter.BindUIUseCase(UIFormType.NodeMapForm, _nodeMapFormUseCase);
OpenHubUI();
}
protected override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds,
float realElapseSeconds)
{
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
GameEntry.CombatNode.OnUpdate(elapseSeconds, realElapseSeconds);
}
protected override void OnLeave(IFsm<IProcedureManager> procedureOwner, bool isShutdown)
{
GameEntry.CombatNode.OnShutdown();
GameEntry.Event.Unsubscribe(NodeMapNodeEnterRequestedEventArgs.EventId, OnNodeMapNodeEnterRequested);
GameEntry.Event.Unsubscribe(CombatFailureReturnEventArgs.EventId, OnCombatFailureReturn);
GameEntry.Event.Unsubscribe(NodeEnterEventArgs.EventId, OnNodeEnter);
GameEntry.Event.Unsubscribe(NodeCompleteEventArgs.EventId, OnNodeComplete);
GameEntry.UIRouter.CloseUI(UIFormType.RepoForm);
GameEntry.UIRouter.CloseUI(UIFormType.NodeMapForm);
GameEntry.UIRouter.CloseUI(UIFormType.MainForm);
_repoFormUseCase = null;
_nodeMapFormUseCase = null;
_currentRunState = null;
base.OnLeave(procedureOwner, isShutdown);
}
#endregion
private void OnNodeEnter(object sender, GameEventArgs e)
{
if (!(e is NodeEnterEventArgs))
{
return;
}
GameEntry.UIRouter.CloseUI(UIFormType.NodeMapForm);
GameEntry.UIRouter.CloseUI(UIFormType.MainForm);
}
private void OnNodeComplete(object sender, GameEventArgs e)
{
if (!(e is NodeCompleteEventArgs args))
{
return;
}
BackpackInventoryData snapshot = args.InventorySnapshotAfterNode;
if (snapshot == null && GameEntry.PlayerInventory != null)
{
snapshot = GameEntry.PlayerInventory.GetInventorySnapshot();
}
AdvanceRunState(true, snapshot);
OpenHubUI();
}
private void OnCombatFailureReturn(object sender, GameEventArgs e)
{
if (!(e is CombatFailureReturnEventArgs))
{
return;
}
BackpackInventoryData snapshot = GameEntry.PlayerInventory != null
? GameEntry.PlayerInventory.GetInventorySnapshot()
: null;
AdvanceRunState(false, snapshot);
OpenHubUI();
}
private void OnNodeMapNodeEnterRequested(object sender, GameEventArgs e)
{
if (!(sender is NodeMapForm) || !(e is NodeMapNodeEnterRequestedEventArgs args))
{
return;
}
RunNodeState currentNode = _currentRunState?.CurrentNode;
if (_currentRunState == null || !_currentRunState.CanEnterCurrentNode || currentNode == null)
{
Log.Warning("ProcedureMain.OnNodeMapNodeEnterRequested() ignored. Current run has no enterable node.");
return;
}
if (args.SequenceIndex != currentNode.SequenceIndex || args.NodeType != currentNode.NodeType)
{
Log.Warning(
"ProcedureMain.OnNodeMapNodeEnterRequested() ignored. Requested={0}#{1}, CurrentNode={2}#{3}.",
args.NodeType,
args.SequenceIndex,
currentNode.NodeType,
currentNode.SequenceIndex);
return;
}
switch (currentNode.NodeType)
{
case RunNodeType.Combat:
case RunNodeType.BossCombat:
if (!HasAvailableParticipantTower())
{
Log.Warning("ProcedureMain blocked combat start. No participant tower is available.");
return;
}
GameEntry.CombatNode.StartCombat(currentNode.LinkedLevelId);
return;
case RunNodeType.Event:
GameEntry.EventNode.StartEvent();
return;
case RunNodeType.Shop:
GameEntry.ShopNode.StartShop();
return;
default:
Log.Warning("ProcedureMain.OnNodeMapNodeEnterRequested() encountered unsupported node type: {0}.", currentNode.NodeType);
return;
}
}
private void AdvanceRunState(bool succeeded, BackpackInventoryData snapshot)
{
if (_currentRunState == null)
{
return;
}
if (!RunStateAdvanceService.TryCompleteCurrentNode(_currentRunState, succeeded, snapshot))
{
return;
}
if (_currentRunState.IsCompleted)
{
Log.Info("ProcedureMain run completed. RunId={0}", _currentRunState.RunId);
return;
}
RunNodeState nextNode = _currentRunState.CurrentNode;
if (nextNode != null)
{
Log.Info(
"ProcedureMain advanced run. RunId={0}, NextNodeType={1}, SequenceIndex={2}, LevelId={3}.",
_currentRunState.RunId,
nextNode.NodeType,
nextNode.SequenceIndex,
nextNode.LinkedLevelId);
}
}
private static bool HasAvailableParticipantTower()
{
return GameEntry.PlayerInventory != null &&
GameEntry.PlayerInventory.GetParticipantTowerSnapshot().Count > 0;
}
private void OpenHubUI()
{
_nodeMapFormUseCase?.SetRunState(_currentRunState);
GameEntry.UIRouter.OpenUI(UIFormType.MainForm);
GameEntry.UIRouter.OpenUI(UIFormType.NodeMapForm);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e6f092ddfab48b74d8e8cc338e4742e4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,7 +1,5 @@
using GameFramework.Event;
using GameFramework.Fsm;
using GameFramework.Procedure;
using GeometryTD.CustomEvent;
using GeometryTD.Definition;
using GeometryTD.UI;
using UnityGameFramework.Runtime;
@@ -14,7 +12,7 @@ namespace GeometryTD.Procedure
public bool GameStart { get; set; }
private RepoFormUseCase _repoFormUseCase;
private MenuFormUseCase _menuFormUseCase;
#region FSM
@@ -27,22 +25,11 @@ namespace GeometryTD.Procedure
{
base.OnEnter(procedureOwner);
GameEntry.Event.Subscribe(CombatFailureReturnEventArgs.EventId, OnCombatFailureReturn);
GameEntry.Event.Subscribe(NodeCompleteEventArgs.EventId, OnNodeComplete);
GameEntry.Event.Subscribe(NodeEnterEventArgs.EventId, OnNodeEnter);
GameStart = false;
GameEntry.EventNode.OnInit();
GameEntry.CombatNode.OnInit(LevelThemeType.Plain);
GameEntry.ShopNode.OnInit();
GameEntry.PlayerInventory?.OnInit();
_repoFormUseCase = new RepoFormUseCase();
GameEntry.UIRouter.BindUIUseCase(UIFormType.RepoForm, _repoFormUseCase);
GameEntry.UIRouter.OpenUI(UIFormType.MainForm);
GameEntry.UIRouter.OpenUI(UIFormType.TestMenuForm);
_menuFormUseCase = new MenuFormUseCase();
GameEntry.UIRouter.BindUIUseCase(UIFormType.MenuForm, _menuFormUseCase);
GameEntry.UIRouter.OpenUI(UIFormType.MenuForm);
}
protected override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds,
@@ -57,44 +44,16 @@ namespace GeometryTD.Procedure
return;
}
GameEntry.CombatNode.OnUpdate(elapseSeconds, realElapseSeconds);
}
protected override void OnLeave(IFsm<IProcedureManager> procedureOwner, bool isShutdown)
{
GameEntry.CombatNode.OnShutdown();
GameEntry.Event.Unsubscribe(CombatFailureReturnEventArgs.EventId, OnCombatFailureReturn);
GameEntry.Event.Unsubscribe(NodeEnterEventArgs.EventId, OnNodeEnter);
GameEntry.Event.Unsubscribe(NodeCompleteEventArgs.EventId, OnNodeComplete);
_repoFormUseCase = null;
GameEntry.UIRouter.CloseUI(UIFormType.MenuForm);
_menuFormUseCase = null;
base.OnLeave(procedureOwner, isShutdown);
}
#endregion
private void OnNodeEnter(object sender, GameEventArgs e)
{
if (!(e is NodeEnterEventArgs)) return;
GameEntry.UIRouter.CloseUI(UIFormType.TestMenuForm);
GameEntry.UIRouter.CloseUI(UIFormType.MainForm);
}
private void OnNodeComplete(object sender, GameEventArgs e)
{
if (!(e is NodeCompleteEventArgs)) return;
GameEntry.UIRouter.OpenUI(UIFormType.TestMenuForm);
GameEntry.UIRouter.OpenUI(UIFormType.MainForm);
}
private void OnCombatFailureReturn(object sender, GameEventArgs e)
{
if (!(e is CombatFailureReturnEventArgs)) return;
GameEntry.UIRouter.OpenUI(UIFormType.TestMenuForm);
GameEntry.UIRouter.OpenUI(UIFormType.MainForm);
}
}
}