补充事件参数 + 完善 UI 设计
- 事件节点在 EventNodeComponent.cs 的 StartEvent/EndEvent 会携带 runId/nodeId/nodeType/sequenceIndex - 商店节点在 ShopNodeComponent.cs 也会带同一套字段 - 战斗节点通过 CombatNodeComponent.cs 把上下文传进 CombatScheduler,再由 CombatRunningPhaseState.cs 发 NodeEnterEventArgs、由 CombatSchedulerFlowCoordinator.cs 发 NodeCompleteEventArgs - NodeCompleteEventArgs.cs 现在新增了 SequenceIndex - 各种 UI 的覆盖问题
This commit is contained in:
parent
5c6f9bf3a4
commit
47ed27bebb
|
|
@ -5,8 +5,8 @@
|
|||
100 主菜单 MenuForm Medium False True
|
||||
101 设置 SettingForm Medium False True
|
||||
102 关于 AboutForm Medium False True
|
||||
110 主界面 MainForm Medium False True
|
||||
111 仓库UI RepoForm Medium False True
|
||||
110 主界面 MainForm Medium False False
|
||||
111 仓库UI RepoForm Medium False False
|
||||
112 大地图UI NodeMapForm Medium False True
|
||||
113 详细信息 ItemDescForm Medium True False
|
||||
114 奖励选择UI RewardSelectForm Medium False True
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using GameFramework.DataTable;
|
|||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.DataTable;
|
||||
using GeometryTD.Definition;
|
||||
using GeometryTD.Procedure;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
|
|
@ -174,7 +175,12 @@ namespace GeometryTD.CustomComponent
|
|||
EnsureCombatRuntimeInitialized();
|
||||
}
|
||||
|
||||
public void StartCombat(int levelId = 0)
|
||||
public void StartCombat(
|
||||
int levelId = 0,
|
||||
string runId = null,
|
||||
int nodeId = 0,
|
||||
RunNodeType nodeType = RunNodeType.None,
|
||||
int sequenceIndex = -1)
|
||||
{
|
||||
if (!EnsureCombatRuntimeInitialized())
|
||||
{
|
||||
|
|
@ -221,7 +227,14 @@ namespace GeometryTD.CustomComponent
|
|||
LastDefeatedEnemyCount = 0;
|
||||
LastGainedCoin = 0;
|
||||
LastGainedGold = 0;
|
||||
if (!_combatScheduler.Start(selectedLevel, phaseList, _selectedSpawnEntriesByPhaseId))
|
||||
if (!_combatScheduler.Start(
|
||||
selectedLevel,
|
||||
phaseList,
|
||||
_selectedSpawnEntriesByPhaseId,
|
||||
runId,
|
||||
nodeId,
|
||||
nodeType,
|
||||
sequenceIndex))
|
||||
{
|
||||
CurrentLevel = null;
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using GeometryTD.CustomEvent;
|
|||
using GeometryTD.DataTable;
|
||||
using GeometryTD.Definition;
|
||||
using GeometryTD.Entity;
|
||||
using GeometryTD.Procedure;
|
||||
using GeometryTD.UI;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
|
@ -67,7 +68,11 @@ namespace GeometryTD.CustomComponent
|
|||
public bool Start(
|
||||
DRLevel level,
|
||||
IReadOnlyList<DRLevelPhase> phases,
|
||||
IReadOnlyDictionary<int, IReadOnlyList<DRLevelSpawnEntry>> spawnEntriesByPhaseId)
|
||||
IReadOnlyDictionary<int, IReadOnlyList<DRLevelSpawnEntry>> spawnEntriesByPhaseId,
|
||||
string runId = null,
|
||||
int nodeId = 0,
|
||||
RunNodeType nodeType = RunNodeType.None,
|
||||
int sequenceIndex = -1)
|
||||
{
|
||||
if (!_initialized || _context.Entity == null)
|
||||
{
|
||||
|
|
@ -89,6 +94,10 @@ namespace GeometryTD.CustomComponent
|
|||
_context.IsFinishAsVictory = true;
|
||||
|
||||
_context.CurrentLevel = level;
|
||||
_context.RunId = runId;
|
||||
_context.NodeId = nodeId;
|
||||
_context.NodeType = nodeType;
|
||||
_context.SequenceIndex = sequenceIndex;
|
||||
_context.CombatInRunResourceManager.InitializeForCombat(level);
|
||||
for (int i = 0; i < phases.Count; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using System.Collections.Generic;
|
|||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.DataTable;
|
||||
using GeometryTD.Definition;
|
||||
using GeometryTD.Procedure;
|
||||
using GeometryTD.UI;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
|
@ -55,6 +56,10 @@ namespace GeometryTD.CustomComponent
|
|||
_context.IsFinishAsVictory = true;
|
||||
_context.IsCompleted = false;
|
||||
_context.NodeEnterFired = false;
|
||||
_context.RunId = null;
|
||||
_context.NodeId = 0;
|
||||
_context.NodeType = RunNodeType.None;
|
||||
_context.SequenceIndex = -1;
|
||||
}
|
||||
|
||||
public void CleanupAllCombatEntities()
|
||||
|
|
@ -196,7 +201,15 @@ namespace GeometryTD.CustomComponent
|
|||
public void CompleteNormalCombatAndNotify(bool succeeded)
|
||||
{
|
||||
CompleteCombat(succeeded);
|
||||
GameEntry.Event.Fire(this, NodeCompleteEventArgs.Create());
|
||||
GameEntry.Event.Fire(
|
||||
this,
|
||||
NodeCompleteEventArgs.Create(
|
||||
_context.RunId,
|
||||
_context.NodeId,
|
||||
_context.NodeType,
|
||||
_context.SequenceIndex,
|
||||
succeeded,
|
||||
GameEntry.PlayerInventory != null ? GameEntry.PlayerInventory.GetInventorySnapshot() : null));
|
||||
}
|
||||
|
||||
public void CompleteFailureCombatAndNotify()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using GeometryTD.DataTable;
|
||||
using GeometryTD.Entity;
|
||||
using GeometryTD.Procedure;
|
||||
using GeometryTD.UI;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
|
|
@ -29,5 +30,9 @@ namespace GeometryTD.CustomComponent
|
|||
public bool IsCompleted { get; set; }
|
||||
public bool NodeEnterFired { get; set; }
|
||||
public CombatSettlementContext SettlementContext { get; set; }
|
||||
public string RunId { get; set; }
|
||||
public int NodeId { get; set; }
|
||||
public RunNodeType NodeType { get; set; }
|
||||
public int SequenceIndex { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,13 @@ namespace GeometryTD.CustomComponent
|
|||
if (!Context.NodeEnterFired)
|
||||
{
|
||||
Context.NodeEnterFired = true;
|
||||
GameEntry.Event.Fire(Flow, NodeEnterEventArgs.Create());
|
||||
GameEntry.Event.Fire(
|
||||
Flow,
|
||||
NodeEnterEventArgs.Create(
|
||||
Context.RunId,
|
||||
Context.NodeId,
|
||||
Context.NodeType,
|
||||
Context.SequenceIndex));
|
||||
}
|
||||
|
||||
Log.Info(
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using GameFramework.DataTable;
|
|||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.DataTable;
|
||||
using GeometryTD.Definition;
|
||||
using GeometryTD.Procedure;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using GeometryTD.UI;
|
||||
using UnityEngine;
|
||||
|
|
@ -12,6 +13,11 @@ namespace GeometryTD.CustomComponent
|
|||
{
|
||||
public class EventNodeComponent : GameFrameworkComponent
|
||||
{
|
||||
private string _activeRunId;
|
||||
private int _activeNodeId;
|
||||
private RunNodeType _activeNodeType = RunNodeType.None;
|
||||
private int _activeSequenceIndex = -1;
|
||||
|
||||
private readonly List<EventItem> _eventItems = new List<EventItem>();
|
||||
|
||||
private EventFormUseCase _eventFormUseCase;
|
||||
|
|
@ -47,7 +53,7 @@ namespace GeometryTD.CustomComponent
|
|||
Log.Info("EventNodeComponent initialized with {0} events.", _eventItems.Count);
|
||||
}
|
||||
|
||||
public void StartEvent()
|
||||
public void StartEvent(string runId = null, int nodeId = 0, RunNodeType nodeType = RunNodeType.None, int sequenceIndex = -1)
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
|
|
@ -69,15 +75,36 @@ namespace GeometryTD.CustomComponent
|
|||
return;
|
||||
}
|
||||
|
||||
_activeRunId = runId;
|
||||
_activeNodeId = nodeId;
|
||||
_activeNodeType = nodeType;
|
||||
_activeSequenceIndex = sequenceIndex;
|
||||
_eventFormUseCase.SetCurrentEvent(randomEvent);
|
||||
GameEntry.UIRouter.OpenUI(UIFormType.EventForm);
|
||||
GameEntry.Event.Fire(this, NodeEnterEventArgs.Create());
|
||||
GameEntry.Event.Fire(this, NodeEnterEventArgs.Create(runId, nodeId, nodeType, sequenceIndex));
|
||||
}
|
||||
|
||||
public void EndEvent()
|
||||
{
|
||||
GameEntry.UIRouter.CloseUI(UIFormType.EventForm);
|
||||
GameEntry.Event.Fire(this, NodeCompleteEventArgs.Create());
|
||||
GameEntry.Event.Fire(
|
||||
this,
|
||||
NodeCompleteEventArgs.Create(
|
||||
_activeRunId,
|
||||
_activeNodeId,
|
||||
_activeNodeType,
|
||||
_activeSequenceIndex,
|
||||
true,
|
||||
GameEntry.PlayerInventory != null ? GameEntry.PlayerInventory.GetInventorySnapshot() : null));
|
||||
ClearActiveNodeContext();
|
||||
}
|
||||
|
||||
private void ClearActiveNodeContext()
|
||||
{
|
||||
_activeRunId = null;
|
||||
_activeNodeId = 0;
|
||||
_activeNodeType = RunNodeType.None;
|
||||
_activeSequenceIndex = -1;
|
||||
}
|
||||
|
||||
private static EventOption[] ParseOptions(string optionsRaw)
|
||||
|
|
|
|||
|
|
@ -2,11 +2,17 @@ using GeometryTD.UI;
|
|||
using UnityGameFramework.Runtime;
|
||||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.Definition;
|
||||
using GeometryTD.Procedure;
|
||||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
public class ShopNodeComponent : GameFrameworkComponent
|
||||
{
|
||||
private string _activeRunId;
|
||||
private int _activeNodeId;
|
||||
private RunNodeType _activeNodeType = RunNodeType.None;
|
||||
private int _activeSequenceIndex = -1;
|
||||
|
||||
private ShopFormUseCase _shopFormUseCase;
|
||||
private bool _initialized;
|
||||
|
||||
|
|
@ -22,7 +28,7 @@ namespace GeometryTD.CustomComponent
|
|||
_initialized = true;
|
||||
}
|
||||
|
||||
public void StartShop()
|
||||
public void StartShop(string runId = null, int nodeId = 0, RunNodeType nodeType = RunNodeType.None, int sequenceIndex = -1)
|
||||
{
|
||||
if (!_initialized)
|
||||
{
|
||||
|
|
@ -35,14 +41,35 @@ namespace GeometryTD.CustomComponent
|
|||
return;
|
||||
}
|
||||
|
||||
_activeRunId = runId;
|
||||
_activeNodeId = nodeId;
|
||||
_activeNodeType = nodeType;
|
||||
_activeSequenceIndex = sequenceIndex;
|
||||
GameEntry.UIRouter.OpenUI(UIFormType.ShopForm);
|
||||
GameEntry.Event.Fire(this, NodeEnterEventArgs.Create());
|
||||
GameEntry.Event.Fire(this, NodeEnterEventArgs.Create(runId, nodeId, nodeType, sequenceIndex));
|
||||
}
|
||||
|
||||
public void EndShop()
|
||||
{
|
||||
GameEntry.UIRouter.CloseUI(UIFormType.ShopForm);
|
||||
GameEntry.Event.Fire(this, NodeCompleteEventArgs.Create());
|
||||
GameEntry.Event.Fire(
|
||||
this,
|
||||
NodeCompleteEventArgs.Create(
|
||||
_activeRunId,
|
||||
_activeNodeId,
|
||||
_activeNodeType,
|
||||
_activeSequenceIndex,
|
||||
true,
|
||||
GameEntry.PlayerInventory != null ? GameEntry.PlayerInventory.GetInventorySnapshot() : null));
|
||||
ClearActiveNodeContext();
|
||||
}
|
||||
|
||||
private void ClearActiveNodeContext()
|
||||
{
|
||||
_activeRunId = null;
|
||||
_activeNodeId = 0;
|
||||
_activeNodeType = RunNodeType.None;
|
||||
_activeSequenceIndex = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ namespace GeometryTD.CustomEvent
|
|||
|
||||
public RunNodeType NodeType { get; private set; }
|
||||
|
||||
public int SequenceIndex { get; private set; }
|
||||
|
||||
public bool Succeeded { get; private set; }
|
||||
|
||||
public BackpackInventoryData InventorySnapshotAfterNode { get; private set; }
|
||||
|
|
@ -28,13 +30,14 @@ namespace GeometryTD.CustomEvent
|
|||
|
||||
public static NodeCompleteEventArgs Create()
|
||||
{
|
||||
return Create(null, 0, RunNodeType.None, true, null);
|
||||
return Create(null, 0, RunNodeType.None, -1, true, null);
|
||||
}
|
||||
|
||||
public static NodeCompleteEventArgs Create(
|
||||
string runId,
|
||||
int nodeId,
|
||||
RunNodeType nodeType,
|
||||
int sequenceIndex,
|
||||
bool succeeded,
|
||||
BackpackInventoryData inventorySnapshotAfterNode)
|
||||
{
|
||||
|
|
@ -42,6 +45,7 @@ namespace GeometryTD.CustomEvent
|
|||
args.RunId = runId;
|
||||
args.NodeId = nodeId;
|
||||
args.NodeType = nodeType;
|
||||
args.SequenceIndex = sequenceIndex;
|
||||
args.Succeeded = succeeded;
|
||||
args.InventorySnapshotAfterNode = InventoryCloneUtility.CloneInventory(inventorySnapshotAfterNode);
|
||||
|
||||
|
|
@ -53,6 +57,7 @@ namespace GeometryTD.CustomEvent
|
|||
RunId = null;
|
||||
NodeId = 0;
|
||||
NodeType = RunNodeType.None;
|
||||
SequenceIndex = -1;
|
||||
Succeeded = false;
|
||||
InventorySnapshotAfterNode = null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,11 +78,45 @@ namespace GeometryTD.Procedure
|
|||
|
||||
private void OnNodeEnter(object sender, GameEventArgs e)
|
||||
{
|
||||
if (!(e is NodeEnterEventArgs))
|
||||
if (!(e is NodeEnterEventArgs args))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(args.RunId) &&
|
||||
_currentRunState != null &&
|
||||
!string.Equals(args.RunId, _currentRunState.RunId))
|
||||
{
|
||||
Log.Warning(
|
||||
"ProcedureMain.OnNodeEnter() ignored. EventRunId={0}, CurrentRunId={1}.",
|
||||
args.RunId,
|
||||
_currentRunState.RunId);
|
||||
return;
|
||||
}
|
||||
|
||||
RunNodeState currentNode = _currentRunState?.CurrentNode;
|
||||
if (currentNode != null &&
|
||||
((args.NodeId > 0 && args.NodeId != currentNode.NodeId) ||
|
||||
(args.NodeType != RunNodeType.None && args.NodeType != currentNode.NodeType) ||
|
||||
(args.SequenceIndex >= 0 && args.SequenceIndex != currentNode.SequenceIndex)))
|
||||
{
|
||||
Log.Warning(
|
||||
"ProcedureMain.OnNodeEnter() node mismatch. EventNodeId={0}, EventNodeType={1}, EventSequenceIndex={2}; CurrentNodeId={3}, CurrentNodeType={4}, CurrentSequenceIndex={5}.",
|
||||
args.NodeId,
|
||||
args.NodeType,
|
||||
args.SequenceIndex,
|
||||
currentNode.NodeId,
|
||||
currentNode.NodeType,
|
||||
currentNode.SequenceIndex);
|
||||
}
|
||||
|
||||
Log.Info(
|
||||
"ProcedureMain.OnNodeEnter() accepted. RunId={0}, NodeId={1}, NodeType={2}, SequenceIndex={3}.",
|
||||
string.IsNullOrWhiteSpace(args.RunId) ? _currentRunState?.RunId : args.RunId,
|
||||
args.NodeId,
|
||||
args.NodeType,
|
||||
args.SequenceIndex);
|
||||
|
||||
GameEntry.UIRouter.CloseUI(UIFormType.NodeMapForm);
|
||||
GameEntry.UIRouter.CloseUI(UIFormType.MainForm);
|
||||
}
|
||||
|
|
@ -94,13 +128,24 @@ namespace GeometryTD.Procedure
|
|||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(args.RunId) &&
|
||||
_currentRunState != null &&
|
||||
!string.Equals(args.RunId, _currentRunState.RunId))
|
||||
{
|
||||
Log.Warning(
|
||||
"ProcedureMain.OnNodeComplete() ignored. EventRunId={0}, CurrentRunId={1}.",
|
||||
args.RunId,
|
||||
_currentRunState.RunId);
|
||||
return;
|
||||
}
|
||||
|
||||
BackpackInventoryData snapshot = args.InventorySnapshotAfterNode;
|
||||
if (snapshot == null && GameEntry.PlayerInventory != null)
|
||||
{
|
||||
snapshot = GameEntry.PlayerInventory.GetInventorySnapshot();
|
||||
}
|
||||
|
||||
AdvanceRunState(true, snapshot);
|
||||
AdvanceRunState(args.Succeeded, snapshot);
|
||||
OpenHubUI();
|
||||
}
|
||||
|
||||
|
|
@ -153,16 +198,30 @@ namespace GeometryTD.Procedure
|
|||
return;
|
||||
}
|
||||
|
||||
GameEntry.CombatNode.StartCombat(currentNode.LinkedLevelId);
|
||||
GameEntry.CombatNode.StartCombat(
|
||||
currentNode.LinkedLevelId,
|
||||
_currentRunState.RunId,
|
||||
currentNode.NodeId,
|
||||
currentNode.NodeType,
|
||||
currentNode.SequenceIndex);
|
||||
return;
|
||||
case RunNodeType.Event:
|
||||
GameEntry.EventNode.StartEvent();
|
||||
GameEntry.EventNode.StartEvent(
|
||||
_currentRunState.RunId,
|
||||
currentNode.NodeId,
|
||||
currentNode.NodeType,
|
||||
currentNode.SequenceIndex);
|
||||
return;
|
||||
case RunNodeType.Shop:
|
||||
GameEntry.ShopNode.StartShop();
|
||||
GameEntry.ShopNode.StartShop(
|
||||
_currentRunState.RunId,
|
||||
currentNode.NodeId,
|
||||
currentNode.NodeType,
|
||||
currentNode.SequenceIndex);
|
||||
return;
|
||||
default:
|
||||
Log.Warning("ProcedureMain.OnNodeMapNodeEnterRequested() encountered unsupported node type: {0}.", currentNode.NodeType);
|
||||
Log.Warning("ProcedureMain.OnNodeMapNodeEnterRequested() encountered unsupported node type: {0}.",
|
||||
currentNode.NodeType);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -206,8 +265,8 @@ namespace GeometryTD.Procedure
|
|||
private void OpenHubUI()
|
||||
{
|
||||
_nodeMapFormUseCase?.SetRunState(_currentRunState);
|
||||
GameEntry.UIRouter.OpenUI(UIFormType.MainForm);
|
||||
GameEntry.UIRouter.OpenUI(UIFormType.NodeMapForm);
|
||||
GameEntry.UIRouter.OpenUI(UIFormType.MainForm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -108,6 +108,7 @@ namespace GeometryTD.Tests.Editor
|
|||
"run-1",
|
||||
7,
|
||||
RunNodeType.Shop,
|
||||
3,
|
||||
true,
|
||||
inventory);
|
||||
|
||||
|
|
@ -116,6 +117,7 @@ namespace GeometryTD.Tests.Editor
|
|||
Assert.That(eventArgs.RunId, Is.EqualTo("run-1"));
|
||||
Assert.That(eventArgs.NodeId, Is.EqualTo(7));
|
||||
Assert.That(eventArgs.NodeType, Is.EqualTo(RunNodeType.Shop));
|
||||
Assert.That(eventArgs.SequenceIndex, Is.EqualTo(3));
|
||||
Assert.That(eventArgs.Succeeded, Is.True);
|
||||
Assert.That(eventArgs.InventorySnapshotAfterNode.Gold, Is.EqualTo(66));
|
||||
|
||||
|
|
@ -124,6 +126,7 @@ namespace GeometryTD.Tests.Editor
|
|||
Assert.That(eventArgs.RunId, Is.Null);
|
||||
Assert.That(eventArgs.NodeId, Is.EqualTo(0));
|
||||
Assert.That(eventArgs.NodeType, Is.EqualTo(RunNodeType.None));
|
||||
Assert.That(eventArgs.SequenceIndex, Is.EqualTo(-1));
|
||||
Assert.That(eventArgs.Succeeded, Is.False);
|
||||
Assert.That(eventArgs.InventorySnapshotAfterNode, Is.Null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -208,12 +208,12 @@ PrefabInstance:
|
|||
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 200
|
||||
value: 160
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: 200
|
||||
value: 160
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
|
|
@ -275,6 +275,26 @@ PrefabInstance:
|
|||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 7744090569424522082, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: -30
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 7744090569424522082, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: -30
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 7744090569424522082, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 7744090569424522082, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
|
|
@ -372,12 +392,12 @@ PrefabInstance:
|
|||
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: 200
|
||||
value: 160
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: 200
|
||||
value: 160
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
|
|
@ -439,6 +459,26 @@ PrefabInstance:
|
|||
propertyPath: m_LocalEulerAnglesHint.z
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 7744090569424522082, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.x
|
||||
value: -30
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 7744090569424522082, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: m_SizeDelta.y
|
||||
value: -30
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 7744090569424522082, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.x
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 7744090569424522082, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: m_AnchoredPosition.y
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
m_RemovedComponents: []
|
||||
m_RemovedGameObjects: []
|
||||
m_AddedGameObjects: []
|
||||
|
|
|
|||
|
|
@ -999,7 +999,7 @@ MonoBehaviour:
|
|||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 0.2, g: 0.2, b: 0.2, a: 0.5019608}
|
||||
m_Color: {r: 0.2, g: 0.2, b: 0.2, a: 0.8}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
和上一版相比,仓库已经把 Run 相关基础件进一步接到了 `ProcedureMain`,因此这份清单不再把重点放在“有没有 Run 模型”,而是聚焦下面这几个真实阻塞项:
|
||||
|
||||
- 已有 `ProcedureMain + TestMenuForm` 的临时 Run 推进闭环,但还没有正式节点地图 / 节点面板。
|
||||
- 已有 `ProcedureMain + NodeMapForm` 的临时 Run 推进闭环,正式节点面板骨架已经接入流程。
|
||||
- 固定 10 节点顺序已经开始驱动战斗 / 事件 / 商店入口,但节点事件上下文仍然是空载版本。
|
||||
- 出战入口已有“至少有参战塔”的最小校验,但还没收口成严格的最终合法性约束。
|
||||
- 品质 / Tag / 耐久仍然停留在部分实现状态,尚未和 M1 范围完全对齐。
|
||||
|
|
@ -90,25 +90,42 @@
|
|||
- `Assets/GameMain/Scripts/UI/Shop/Controller/ShopFormController.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Shop/View/ShopForm.cs`
|
||||
|
||||
### 7. `NodeMapForm` 五层 UI 已经接入主流程
|
||||
|
||||
- 已新增 `NodeMapFormRawData / UseCase / Controller / Context / View` 和 `NodeItemContext / NodeItem`。
|
||||
- `ProcedureMain` 已不再打开 `TestMenuForm`,而是打开 `NodeMapForm` 作为 Hub 节点入口。
|
||||
- `NodeMapFormController` 会把 `NodeItem` 点击转换为 `NodeMapNodeEnterRequestedEventArgs`,再交给流程层决定是否进入节点。
|
||||
- `NodeItem` 的 `Icon` 已改成通过 `SpriteCacheComponent` 按资源名异步获取,`Bg` 负责表示节点状态。
|
||||
|
||||
关键文件:
|
||||
- `Assets/GameMain/Scripts/UI/Game/RawData/NodeMapFormRawData.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Game/UseCase/NodeMapFormUseCase.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Game/Controller/NodeMapFormController.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Game/Context/NodeMapFormContext.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Game/Context/NodeItemContext.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Game/View/NodeMapForm.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Game/View/NodeItem.cs`
|
||||
- `Assets/GameMain/Scripts/Event/Game/NodeMapNodeEnterRequestedEventArgs.cs`
|
||||
|
||||
## 当前未完成
|
||||
|
||||
### 1. Run 主流程已经形成临时闭环,但还不是正式节点 UI
|
||||
### 1. Run 主流程已经形成基于 `NodeMapForm` 的临时闭环,但还没完全收口
|
||||
|
||||
- `ProcedureMain` 进入后会创建 Run,并打开 `MainForm + TestMenuForm`。
|
||||
- `TestMenuForm` 已不再同时提供三种节点入口,而是通过 `TestMenuFormContext.CurrentNodeType` 只显示当前节点对应的唯一按钮。
|
||||
- 点击按钮后由 `ProcedureMain` 根据当前 `RunState.CurrentNode` 决定是否允许进入战斗 / 事件 / 商店。
|
||||
- `ProcedureMain` 进入后会创建 Run,并打开 `MainForm + NodeMapForm`。
|
||||
- `NodeMapForm` 已经有五层结构,`NodeItem` 也能按当前 `RunState` 刷出 10 个节点。
|
||||
- 点击当前节点后,由 `NodeMapFormController` 发出 `NodeMapNodeEnterRequestedEventArgs`,再由 `ProcedureMain` 根据当前 `RunState.CurrentNode` 决定是否允许进入战斗 / 事件 / 商店。
|
||||
- 节点完成或战斗失败后,`ProcedureMain` 会推进 `RunState`,再重新打开 Hub UI。
|
||||
- 因此当前已经能从开始游戏后按固定顺序推进一局的临时版本。
|
||||
- 因此当前已经不是“测试菜单三选一”,而是“节点地图单入口”的临时版本。
|
||||
|
||||
当前缺口:
|
||||
- UI 仍是测试面板,不是正式节点地图或正式节点信息面板。
|
||||
- `TestMenuFormContext` 目前只传 `CurrentNodeType`,还没有显示节点序号、总数、Boss 标记等关键信息。
|
||||
- `NodeMapForm` 已接入,但当前仍偏 MVP 骨架,缺节点连线、节点说明、Boss 特效等正式表现。
|
||||
- `NodeMapFormContext` 当前只提供基础进度和当前节点信息,还没有更完整的地图展示上下文。
|
||||
- Run 完成后的正式结算 / 收尾表现仍未建立。
|
||||
|
||||
关键文件:
|
||||
- `Assets/GameMain/Scripts/Procedure/ProcedureMain.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Menu/View/TestMenuForm.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Menu/Controller/TestMenuFormController.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Game/View/NodeMapForm.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Game/Controller/NodeMapFormController.cs`
|
||||
|
||||
### 2. 固定 10 节点序列已开始驱动真实流程,但上下文仍不完整
|
||||
|
||||
|
|
@ -131,7 +148,7 @@
|
|||
|
||||
- 现在可以单独打开商店、随机生成组件、购买并退出。
|
||||
- 商店结束后已能通过 `ProcedureMain` 推进当前 `RunState`。
|
||||
- 但退出后仍是回到 `MainForm + TestMenuForm`,而不是真实节点地图或正式节点选择界面。
|
||||
- 但退出后当前回流的是 `MainForm + NodeMapForm` 的 MVP 节点面板,而不是完整表现版地图。
|
||||
|
||||
关键文件:
|
||||
- `Assets/GameMain/Scripts/CustomComponent/ShopNodeComponent.cs`
|
||||
|
|
@ -183,21 +200,21 @@
|
|||
|
||||
结合静态代码检查,当前更接近下面这个状态:
|
||||
|
||||
- `P0-04`:基础模型已完成,并已接入 `ProcedureMain` 的临时 Run 闭环。
|
||||
- `P0-05`:固定 10 节点序列已由 builder + `ProcedureMain` 开始驱动实际流程,但缺完整事件上下文与正式节点 UI。
|
||||
- `P0-06`:节点进入、完成、失败后回 Hub 的临时闭环已存在,但“正式地图/节点界面 + 正式结算”仍未完成。
|
||||
- `P0-04`:基础模型已完成,并已接入 `ProcedureMain + NodeMapForm` 的临时 Run 闭环。
|
||||
- `P0-05`:固定 10 节点序列已由 builder + `ProcedureMain + NodeMapForm` 驱动实际流程,但缺完整事件上下文与地图表现层。
|
||||
- `P0-06`:节点进入、完成、失败后回 `NodeMapForm` 的临时闭环已存在,但正式地图表现与正式结算仍未完成。
|
||||
- `P0-10`:未完成。
|
||||
- `P0-11`:未完成。
|
||||
- `P0-12`:未完成。
|
||||
|
||||
换句话说,仓库已经不再是“还没有 Run 模型 / 10 节点 / 商店最小实现”的状态;真正的缺口是“这些能力已经接成临时可跑版本,但还没收口成正式 M1 主流程表现层与上下文系统”。
|
||||
换句话说,仓库已经不再是“还没有 Run 模型 / 10 节点 / 商店最小实现”的状态;真正的缺口是“这些能力已经接成 `NodeMapForm` 驱动的临时可跑版本,但还没收口成正式 M1 主流程表现层与上下文系统”。
|
||||
|
||||
## 推荐的后续执行顺序
|
||||
|
||||
1. 先把临时 Hub 升级成正式节点面板
|
||||
- 保留 `ProcedureMain` 持有 Run 的做法
|
||||
- 不再把 `TestMenuForm` 当测试菜单,而是改成正式节点信息面板或节点地图
|
||||
- 至少补上当前节点序号、总节点数、节点名称、Boss 标记
|
||||
- 继续以 `NodeMapForm` 为基础补正式节点地图表现
|
||||
- 至少补上节点连线、Boss 视觉强调、当前节点说明和完成态反馈
|
||||
|
||||
2. 再把节点事件改成带上下文的真实推进
|
||||
- `NodeEnterEventArgs` 和 `NodeCompleteEventArgs` 传递 `runId / nodeId / nodeType / sequenceIndex`
|
||||
|
|
@ -218,7 +235,7 @@
|
|||
|
||||
## 当前做变更时要记住的约束
|
||||
|
||||
- 不要再把 `TestMenuForm` 维持成“测试菜单”语义。
|
||||
- 不要再把 Hub 退回 `TestMenuForm` 语义。
|
||||
- 优先补“临时闭环 -> 正式节点 UI / 正式上下文”的收口,不要继续只加单点功能。
|
||||
- 商店已经接入 Run,下一步重点不是继续扩商店,而是把 Hub/UI 做正式。
|
||||
- 若 M1 最终不做完整耐久 / 红色品质,要先同步文档再改代码目标。
|
||||
|
|
@ -233,8 +250,9 @@
|
|||
- `Assets/GameMain/Scripts/Procedure/RunStateFactory.cs`
|
||||
- `Assets/GameMain/Scripts/Procedure/RunStateAdvanceService.cs`
|
||||
- `Assets/GameMain/Scripts/Procedure/FixedRunNodeSequenceBuilder.cs`
|
||||
- 临时 Hub / 节点入口:
|
||||
- `Assets/GameMain/Scripts/UI/Menu/Controller/TestMenuFormController.cs`
|
||||
- 当前 Hub / 节点入口:
|
||||
- `Assets/GameMain/Scripts/UI/Game/Controller/NodeMapFormController.cs`
|
||||
- `Assets/GameMain/Scripts/UI/Game/View/NodeMapForm.cs`
|
||||
- 战斗节点 facade:
|
||||
- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatNodeComponent.cs`
|
||||
- 事件节点:
|
||||
|
|
@ -251,4 +269,4 @@
|
|||
|
||||
- 这份清单基于 2026-03-08 的静态代码检查更新。
|
||||
- 本次已修正上一版中“Run 模型不存在”“10 节点未实现”“商店节点基本未实现”等过期判断。
|
||||
- 当前最值得优先推进的是:`ProcedureMain 继续收口 Run 流程 -> 节点事件带上下文 -> 战斗按节点关卡进入 -> 出战校验`。
|
||||
- 当前最值得优先推进的是:`NodeMapForm 继续收口表现层 -> 节点事件带上下文 -> 战斗按节点关卡进入 -> 出战校验`。
|
||||
|
|
|
|||
|
|
@ -16,9 +16,9 @@
|
|||
| [x] | P0-01 | 冻结 MVP 范围(只保留:战斗节点/事件节点/商店节点/节点后组装) | `docs/MVP-Scope.md` | 明确“做/不做”清单,团队评审通过 |
|
||||
| [x] | P0-02 | 补齐数据表:组件、配件、敌人、波次、节点、事件、商店商品 | `Assets/GameMain/DataTables/*.txt` | 游戏启动可无报错加载全部新增表 |
|
||||
| [x] | P0-03 | 新增/完善 DataRow 解析类 | `Assets/GameMain/Scripts/DataTable/*.cs` | 每个新增表都有对应 DR 类并成功解析 |
|
||||
| [~] | P0-04 | 建立单局 Run 状态模型(金币、生命、库存、当前节点) | `Assets/GameMain/Scripts/Procedure/` | 已有 `RunState` / 推进模型 / 测试,并已接入 `ProcedureMain` 的临时 Run 闭环,但还不是正式节点 UI |
|
||||
| [~] | P0-05 | 实现 10 节点地图生成(最后节点固定 Boss) | `Assets/GameMain/Scripts/Procedure/`<br>`Assets/GameMain/Scripts/Scene/` | 已有固定 10 节点序列 builder 与测试,且已开始驱动真实流程,但节点事件上下文与正式节点面板仍未完成 |
|
||||
| [~] | P0-06 | 实现节点选择与跳转流程(战斗/事件/商店) | `Assets/GameMain/Scripts/Procedure/` | `ProcedureMain + TestMenuForm` 的临时闭环已可推进战斗/事件/商店,但仍缺正式节点地图/节点面板与正式结算收尾 |
|
||||
| [~] | P0-04 | 建立单局 Run 状态模型(金币、生命、库存、当前节点) | `Assets/GameMain/Scripts/Procedure/` | 已有 `RunState` / 推进模型 / 测试,并已接入 `ProcedureMain + NodeMapForm` 的临时 Run 闭环 |
|
||||
| [~] | P0-05 | 实现 10 节点地图生成(最后节点固定 Boss) | `Assets/GameMain/Scripts/Procedure/`<br>`Assets/GameMain/Scripts/Scene/` | 已有固定 10 节点序列 builder 与测试,且已由 `NodeMapForm` 驱动节点入口,但节点事件上下文与地图表现层仍未完成 |
|
||||
| [~] | P0-06 | 实现节点选择与跳转流程(战斗/事件/商店) | `Assets/GameMain/Scripts/Procedure/` | `ProcedureMain + NodeMapForm` 的临时闭环已可推进战斗/事件/商店,但仍缺完整地图表现、正式结算收尾与节点上下文回流 |
|
||||
| [x] | P0-07 | 战斗节点基础玩法:放置塔、出怪、基地扣血、胜负判定 | `Assets/GameMain/Scripts/Entity/`<br>`Assets/GameMain/Scripts/Scene/` | 可完整打一场并得到胜利/失败结果 |
|
||||
| [x] | P0-08 | 胜利波次与结算规则(100/80/50/<50) | `Assets/GameMain/Scripts/Procedure/` | 结算奖励与惩罚严格匹配设计文档 |
|
||||
| [x] | P0-09 | 敌人掉落与关卡奖励(组件/配件/金币) | `Assets/GameMain/Scripts/Entity/` | 战斗结束能发放掉落并写入库存 |
|
||||
|
|
@ -55,7 +55,7 @@
|
|||
|
||||
## 本周建议开工顺序
|
||||
|
||||
1. 先把 `P0-04` ~ `P0-06` 从“临时闭环”收口成正式节点面板 / 节点地图,并补齐节点事件上下文
|
||||
1. 先把 `P0-04` ~ `P0-06` 从“`NodeMapForm` 临时闭环”收口成正式节点地图表现,并补齐节点事件上下文
|
||||
2. 完成 `P0-10`(把“至少有参战塔”提升为“满足完整合法参战条件才能出战”)
|
||||
3. 再处理 `P0-11` ~ `P0-12`(品质 / Tag / 耐久是否纳入 M1 需先统一范围)
|
||||
|
||||
|
|
|
|||
BIN
数据表/UIForm.xlsx
BIN
数据表/UIForm.xlsx
Binary file not shown.
Loading…
Reference in New Issue