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

1
.gitignore vendored
View File

@ -104,3 +104,4 @@ InitTestScene*.unity*
/[Aa]ssets/RawResources.meta /[Aa]ssets/RawResources.meta
/.dotnet /.dotnet
/.idea /.idea
~$*.xlsx

View File

@ -1,23 +1,23 @@
# Id 列1 DurationSeconds EndType EndParam # Id 列1 DurationSeconds EndType EndParam
# int int PhaseEndType string # int int PhaseEndType string
# 关卡阶段号 策划备注 波次持续时间 波次结束条件 结束参数 # 关卡阶段号 策划备注 波次持续时间 波次结束条件 结束参数
1001 平原1.1 60 TimeElapsed 60 1001 平原1.1 55 TimeElapsed 60
1002 平原1.2 60 TimeElapsed 60 1002 平原1.2 55 TimeElapsed 60
1003 平原1.3 60 TimeElapsed 60 1003 平原1.3 55 TimeElapsed 60
1004 平原1.4 60 EnemiesCleared 60 1004 平原1.4 55 EnemiesCleared
1005 平原1.* 0 1005 平原1.* 0
2001 平原2.1 60 TimeElapsed 60 2001 平原2.1 55 TimeElapsed 60
2002 平原2.2 60 TimeElapsed 60 2002 平原2.2 55 TimeElapsed 60
2003 平原2.3 60 TimeElapsed 60 2003 平原2.3 55 TimeElapsed 60
2004 平原2.4 60 EnemiesCleared 60 2004 平原2.4 55 EnemiesCleared
2005 平原2.* 0 2005 平原2.* 0
3001 平原3.1 60 TimeElapsed 60 3001 平原3.1 55 TimeElapsed 60
3002 平原3.2 60 TimeElapsed 60 3002 平原3.2 55 TimeElapsed 60
3003 平原3.3 60 TimeElapsed 60 3003 平原3.3 55 TimeElapsed 60
3004 平原3.4 60 EnemiesCleared 60 3004 平原3.4 55 EnemiesCleared
3005 平原3.* 0 3005 平原3.* 0
4001 平原4.1 60 TimeElapsed 60 4001 平原4.1 55 TimeElapsed 60
4002 平原4.2 60 TimeElapsed 60 4002 平原4.2 55 TimeElapsed 60
4003 平原4.3 60 TimeElapsed 60 4003 平原4.3 55 TimeElapsed 60
4004 平原4.4 60 TimeElapsed 60 4004 平原4.4 55 TimeElapsed 60
4005 平原4.5 0 BossDead 4005 平原4.5 0 BossDead

View File

@ -1,33 +1,33 @@
# Id 列1 SpawnPointId StartTime EntryType EnemyId Count Interval Duration Gap # Id 列1 SpawnPointId StartTime EntryType EnemyId Count Interval Duration Gap
# int int int EntryType int int float int float # int int int EntryType int int float int float
# 阶段条目号 策划备注 敌人出生口Id 相对时间 条目类型 敌人Id 单次出怪数量 出怪间隔 持续时间 单怪出生时间间隔 # 阶段条目号 策划备注 敌人出生口Id 相对时间 条目类型 敌人Id 单次出怪数量 出怪间隔 持续时间 单怪出生时间间隔
1001001 1 5 Stream 1 3 5 60 0.5 1001001 1 5 Stream 1 3 5 40 0.5
1001002 2 5 Burst 1 10 0 0 0.2 1001002 2 5 Burst 1 10 0 0 0.2
1002001 1 3 Stream 1 3 5 60 0.5 1002001 1 3 Stream 1 3 5 40 0.5
1002002 2 3 Burst 1 10 0 0 0.2 1002002 2 3 Burst 1 10 0 0 0.2
1003001 1 5 Stream 1 3 5 60 0.5 1003001 1 5 Stream 1 3 5 40 0.5
1003002 2 5 Burst 1 10 0 0 0.2 1003002 2 5 Burst 1 10 0 0 0.2
1004001 1 3 Stream 1 3 5 60 0.5 1004001 1 3 Stream 1 3 5 40 0.5
1004002 2 3 Burst 1 10 0 0 0.2 1004002 2 3 Burst 1 10 0 0 0.2
1005001 1 5 Stream 1 3 5 60 0.5 1005001 1 5 Stream 1 3 5 40 0.5
1005002 2 5 Burst 1 10 0 0 0.2 1005002 2 5 Burst 1 10 0 0 0.2
2001001 1 5 Stream 1 3 5 60 0.5 2001001 1 5 Stream 1 3 5 40 0.5
2002001 1 5 Burst 1 10 0 0 0.2 2002001 1 5 Burst 1 10 0 0 0.2
2003001 1 5 Stream 1 3 5 60 0.5 2003001 1 5 Stream 1 3 5 40 0.5
2004001 1 5 Burst 1 10 0 0 0.2 2004001 1 5 Burst 1 10 0 0 0.2
2005001 1 5 Stream 1 3 5 60 0.5 2005001 1 5 Stream 1 3 5 40 0.5
3001001 1 5 Stream 1 3 5 60 0.5 3001001 1 5 Stream 1 3 5 40 0.5
3001002 2 5 Burst 1 10 0 0 0.2 3001002 2 5 Burst 1 10 0 0 0.2
3002001 1 3 Stream 1 3 5 60 0.5 3002001 1 3 Stream 1 3 5 40 0.5
3002002 2 3 Burst 1 10 0 0 0.2 3002002 2 3 Burst 1 10 0 0 0.2
3003001 1 5 Stream 1 3 5 60 0.5 3003001 1 5 Stream 1 3 5 40 0.5
3003002 2 5 Burst 1 10 0 0 0.2 3003002 2 5 Burst 1 10 0 0 0.2
3004001 1 3 Stream 1 3 5 60 0.5 3004001 1 3 Stream 1 3 5 40 0.5
3004002 2 3 Burst 1 10 0 0 0.2 3004002 2 3 Burst 1 10 0 0 0.2
3005001 1 5 Stream 1 3 5 60 0.5 3005001 1 5 Stream 1 3 5 40 0.5
3005002 2 5 Burst 1 10 0 0 0.2 3005002 2 5 Burst 1 10 0 0 0.2
4001001 1 5 Stream 1 3 5 60 0.5 4001001 1 5 Stream 1 3 5 40 0.5
4002001 1 5 Burst 1 10 0 0 0.2 4002001 1 5 Burst 1 10 0 0 0.2
4003001 1 5 Stream 1 3 5 60 0.5 4003001 1 5 Stream 1 3 5 40 0.5
4004001 1 5 Burst 1 10 0 0 0.2 4004001 1 5 Burst 1 10 0 0 0.2
4005001 1 5 Boss 2 1 5 60 0 4005001 1 5 Boss 2 1 5 40 0

View File

@ -7,9 +7,10 @@
102 关于 AboutForm Medium False True 102 关于 AboutForm Medium False True
110 主界面 MainForm Medium False True 110 主界面 MainForm Medium False True
111 仓库UI RepoForm Medium False True 111 仓库UI RepoForm Medium False True
112 详细信息 ItemDescForm Medium True False 112 大地图UI NodeMapForm Medium False True
113 奖励选择UI RewardSelectForm Medium False True 113 详细信息 ItemDescForm Medium True False
130 事件UI EventForm Medium False False 114 奖励选择UI RewardSelectForm Medium False True
130 事件UI EventForm Medium False True
140 战斗信息UI CombatInfoForm Medium False False 140 战斗信息UI CombatInfoForm Medium False False
141 战斗结束UI CombatFinishForm Medium False True 141 战斗结束UI CombatFinishForm Medium False True
142 战斗选择UI CombatSelectForm Overlay False False 142 战斗选择UI CombatSelectForm Overlay False False

View File

@ -371,7 +371,7 @@ Transform:
m_GameObject: {fileID: 961739749} m_GameObject: {fileID: 961739749}
serializedVersion: 2 serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 1, z: -10} m_LocalPosition: {x: 0, y: 0, z: -10}
m_LocalScale: {x: 1, y: 1, z: 1} m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0 m_ConstrainProportionsScale: 0
m_Children: [] m_Children: []

View File

@ -174,7 +174,7 @@ namespace GeometryTD.CustomComponent
EnsureCombatRuntimeInitialized(); EnsureCombatRuntimeInitialized();
} }
public void StartCombat() public void StartCombat(int levelId = 0)
{ {
if (!EnsureCombatRuntimeInitialized()) if (!EnsureCombatRuntimeInitialized())
{ {
@ -182,9 +182,14 @@ namespace GeometryTD.CustomComponent
return; return;
} }
if (!TrySelectRandomLevel(out DRLevel selectedLevel)) bool hasLevel = levelId > 0
? TryGetLevelById(levelId, out DRLevel selectedLevel)
: TrySelectRandomLevel(out selectedLevel);
if (!hasLevel)
{ {
Log.Warning("CombatNodeComponent has no level cache. Call OnInit(levelThemeType) first."); Log.Warning(
"CombatNodeComponent start failed. LevelId={0}. Missing cached level data or invalid level id.",
levelId);
return; return;
} }
@ -348,6 +353,17 @@ namespace GeometryTD.CustomComponent
return _levelsById.TryGetValue(selectedLevelId, out level); return _levelsById.TryGetValue(selectedLevelId, out level);
} }
private bool TryGetLevelById(int levelId, out DRLevel level)
{
level = null;
if (levelId <= 0)
{
return false;
}
return _levelsById.TryGetValue(levelId, out level);
}
private int CountPhases() private int CountPhases()
{ {
int count = 0; int count = 0;

View File

@ -15,7 +15,6 @@ namespace GeometryTD.CustomComponent
private readonly List<EventItem> _eventItems = new List<EventItem>(); private readonly List<EventItem> _eventItems = new List<EventItem>();
private EventFormUseCase _eventFormUseCase; private EventFormUseCase _eventFormUseCase;
private EventFormController _eventFormController;
private bool _initialized; private bool _initialized;
public void OnInit() public void OnInit()
@ -42,11 +41,7 @@ namespace GeometryTD.CustomComponent
_eventFormUseCase = new EventFormUseCase(); _eventFormUseCase = new EventFormUseCase();
} }
if (_eventFormController == null) GameEntry.UIRouter.BindUIUseCase(UIFormType.EventForm, _eventFormUseCase);
{
_eventFormController = new EventFormController();
_eventFormController.BindUseCase(_eventFormUseCase);
}
_initialized = true; _initialized = true;
Log.Info("EventNodeComponent initialized with {0} events.", _eventItems.Count); Log.Info("EventNodeComponent initialized with {0} events.", _eventItems.Count);
@ -68,14 +63,14 @@ namespace GeometryTD.CustomComponent
int index = Random.Range(0, _eventItems.Count); int index = Random.Range(0, _eventItems.Count);
EventItem randomEvent = _eventItems[index]; EventItem randomEvent = _eventItems[index];
if (_eventFormUseCase == null || _eventFormController == null) if (_eventFormUseCase == null)
{ {
Log.Warning("EventNodeComponent StartEvent failed. Event form is not initialized."); Log.Warning("EventNodeComponent StartEvent failed. Event form is not initialized.");
return; return;
} }
_eventFormUseCase.SetCurrentEvent(randomEvent); _eventFormUseCase.SetCurrentEvent(randomEvent);
_eventFormController.OpenUI(); GameEntry.UIRouter.OpenUI(UIFormType.EventForm);
GameEntry.Event.Fire(this, NodeEnterEventArgs.Create()); GameEntry.Event.Fire(this, NodeEnterEventArgs.Create());
} }

View File

@ -1,19 +1,5 @@
//------------------------------------------------------------ using System.IO;
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
// 此文件由工具自动生成,请勿直接修改。
// 生成时间2021-06-16 21:54:35.652
//------------------------------------------------------------
using GameFramework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text; using System.Text;
using UnityEngine;
using UnityGameFramework.Runtime; using UnityGameFramework.Runtime;
namespace GeometryTD.DataTable namespace GeometryTD.DataTable
@ -28,49 +14,27 @@ namespace GeometryTD.DataTable
/// <summary> /// <summary>
/// 获取界面编号。 /// 获取界面编号。
/// </summary> /// </summary>
public override int Id public override int Id => m_Id;
{
get
{
return m_Id;
}
}
/// <summary> /// <summary>
/// 获取资源名称。 /// 获取资源名称。
/// </summary> /// </summary>
public string AssetName public string AssetName { get; private set; }
{
get;
private set;
}
/// <summary> /// <summary>
/// 获取界面组名称。 /// 获取界面组名称。
/// </summary> /// </summary>
public string UIGroupName public string UIGroupName { get; private set; }
{
get;
private set;
}
/// <summary> /// <summary>
/// 获取是否允许多个界面实例。 /// 获取是否允许多个界面实例。
/// </summary> /// </summary>
public bool AllowMultiInstance public bool AllowMultiInstance { get; private set; }
{
get;
private set;
}
/// <summary> /// <summary>
/// 获取是否暂停被其覆盖的界面。 /// 获取是否暂停被其覆盖的界面。
/// </summary> /// </summary>
public bool PauseCoveredUIForm public bool PauseCoveredUIForm { get; private set; }
{
get;
private set;
}
public override bool ParseDataRow(string dataRowString, object userData) public override bool ParseDataRow(string dataRowString, object userData)
{ {

View File

@ -37,15 +37,20 @@
/// </summary> /// </summary>
RepoForm = 111, RepoForm = 111,
/// <summary>
/// 节点地图界面。
/// </summary>
NodeMapForm = 112,
/// <summary> /// <summary>
/// 道具详细信息界面。 /// 道具详细信息界面。
/// </summary> /// </summary>
ItemDescForm = 112, ItemDescForm = 113,
/// <summary> /// <summary>
/// 奖励三选一界面。 /// 奖励三选一界面。
/// </summary> /// </summary>
RewardSelectForm = 113, RewardSelectForm = 114,
/// <summary> /// <summary>
/// 事件节点界面。 /// 事件节点界面。

View File

@ -0,0 +1,26 @@
using GameFramework;
using GameFramework.Event;
namespace GeometryTD.CustomEvent
{
public sealed class NodeMapNodeClickEventArgs : GameEventArgs
{
public static int EventId => typeof(NodeMapNodeClickEventArgs).GetHashCode();
public override int Id => EventId;
public int SequenceIndex { get; private set; }
public static NodeMapNodeClickEventArgs Create(int sequenceIndex)
{
NodeMapNodeClickEventArgs args = ReferencePool.Acquire<NodeMapNodeClickEventArgs>();
args.SequenceIndex = sequenceIndex;
return args;
}
public override void Clear()
{
SequenceIndex = -1;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f16aabf150fd6f640ad6e2ab01705d4f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,43 @@
using GameFramework;
using GameFramework.Event;
using GeometryTD.Procedure;
namespace GeometryTD.CustomEvent
{
public sealed class NodeMapNodeEnterRequestedEventArgs : GameEventArgs
{
public static int EventId => typeof(NodeMapNodeEnterRequestedEventArgs).GetHashCode();
public override int Id => EventId;
public string RunId { get; private set; }
public int NodeId { get; private set; }
public RunNodeType NodeType { get; private set; }
public int SequenceIndex { get; private set; }
public static NodeMapNodeEnterRequestedEventArgs Create(
string runId,
int nodeId,
RunNodeType nodeType,
int sequenceIndex)
{
NodeMapNodeEnterRequestedEventArgs args = ReferencePool.Acquire<NodeMapNodeEnterRequestedEventArgs>();
args.RunId = runId;
args.NodeId = nodeId;
args.NodeType = nodeType;
args.SequenceIndex = sequenceIndex;
return args;
}
public override void Clear()
{
RunId = null;
NodeId = 0;
NodeType = RunNodeType.None;
SequenceIndex = -1;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ef66951469c024d49a35903ac4c6eb13
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6892232c51df8e1439ccc908fb93307b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,21 @@
using GameFramework;
using GameFramework.Event;
namespace GeometryTD.CustomEvent
{
public class MenuExitRequestedEventArgs : GameEventArgs
{
public static int EventId => typeof(MenuExitRequestedEventArgs).GetHashCode();
public override int Id => EventId;
public static MenuExitRequestedEventArgs Create()
{
return ReferencePool.Acquire<MenuExitRequestedEventArgs>();
}
public override void Clear()
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f6b431184ddeace4489032ecdd5996b8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,21 @@
using GameFramework;
using GameFramework.Event;
namespace GeometryTD.CustomEvent
{
public class MenuSettingsRequestedEventArgs : GameEventArgs
{
public static int EventId => typeof(MenuSettingsRequestedEventArgs).GetHashCode();
public override int Id => EventId;
public static MenuSettingsRequestedEventArgs Create()
{
return ReferencePool.Acquire<MenuSettingsRequestedEventArgs>();
}
public override void Clear()
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3b9028de1ea48854caaafc4c9022319a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,21 @@
using GameFramework;
using GameFramework.Event;
namespace GeometryTD.CustomEvent
{
public class MenuStartRequestedEventArgs : GameEventArgs
{
public static int EventId => typeof(MenuStartRequestedEventArgs).GetHashCode();
public override int Id => EventId;
public static MenuStartRequestedEventArgs Create()
{
return ReferencePool.Acquire<MenuStartRequestedEventArgs>();
}
public override void Clear()
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b6605592d400a4b478c9380e0c97ad3a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d17e5e91c45a8814c954edf31b063100
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -86,7 +86,7 @@ namespace GeometryTD.Procedure
ChangeState<ProcedureMenu>(procedureOwner); ChangeState<ProcedureMenu>(procedureOwner);
break; break;
case SceneType.Main: case SceneType.Main:
ChangeState<ProcedureTest>(procedureOwner); ChangeState<ProcedureMain>(procedureOwner);
break; break;
default: default:
Log.Debug($"Scene {sceneType.ToString()} don't configure a procedure"); Log.Debug($"Scene {sceneType.ToString()} don't configure a procedure");

View File

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

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e6f092ddfab48b74d8e8cc338e4742e4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,7 +1,5 @@
using GameFramework.Event;
using GameFramework.Fsm; using GameFramework.Fsm;
using GameFramework.Procedure; using GameFramework.Procedure;
using GeometryTD.CustomEvent;
using GeometryTD.Definition; using GeometryTD.Definition;
using GeometryTD.UI; using GeometryTD.UI;
using UnityGameFramework.Runtime; using UnityGameFramework.Runtime;
@ -14,7 +12,7 @@ namespace GeometryTD.Procedure
public bool GameStart { get; set; } public bool GameStart { get; set; }
private RepoFormUseCase _repoFormUseCase; private MenuFormUseCase _menuFormUseCase;
#region FSM #region FSM
@ -27,22 +25,11 @@ namespace GeometryTD.Procedure
{ {
base.OnEnter(procedureOwner); base.OnEnter(procedureOwner);
GameEntry.Event.Subscribe(CombatFailureReturnEventArgs.EventId, OnCombatFailureReturn);
GameEntry.Event.Subscribe(NodeCompleteEventArgs.EventId, OnNodeComplete);
GameEntry.Event.Subscribe(NodeEnterEventArgs.EventId, OnNodeEnter);
GameStart = false; GameStart = false;
GameEntry.EventNode.OnInit(); _menuFormUseCase = new MenuFormUseCase();
GameEntry.CombatNode.OnInit(LevelThemeType.Plain); GameEntry.UIRouter.BindUIUseCase(UIFormType.MenuForm, _menuFormUseCase);
GameEntry.ShopNode.OnInit(); GameEntry.UIRouter.OpenUI(UIFormType.MenuForm);
GameEntry.PlayerInventory?.OnInit();
_repoFormUseCase = new RepoFormUseCase();
GameEntry.UIRouter.BindUIUseCase(UIFormType.RepoForm, _repoFormUseCase);
GameEntry.UIRouter.OpenUI(UIFormType.MainForm);
GameEntry.UIRouter.OpenUI(UIFormType.TestMenuForm);
} }
protected override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds, protected override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds,
@ -57,44 +44,16 @@ namespace GeometryTD.Procedure
return; return;
} }
GameEntry.CombatNode.OnUpdate(elapseSeconds, realElapseSeconds);
} }
protected override void OnLeave(IFsm<IProcedureManager> procedureOwner, bool isShutdown) protected override void OnLeave(IFsm<IProcedureManager> procedureOwner, bool isShutdown)
{ {
GameEntry.CombatNode.OnShutdown(); GameEntry.UIRouter.CloseUI(UIFormType.MenuForm);
GameEntry.Event.Unsubscribe(CombatFailureReturnEventArgs.EventId, OnCombatFailureReturn); _menuFormUseCase = null;
GameEntry.Event.Unsubscribe(NodeEnterEventArgs.EventId, OnNodeEnter);
GameEntry.Event.Unsubscribe(NodeCompleteEventArgs.EventId, OnNodeComplete);
_repoFormUseCase = null;
base.OnLeave(procedureOwner, isShutdown); base.OnLeave(procedureOwner, isShutdown);
} }
#endregion #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);
}
} }
} }

View File

@ -0,0 +1,16 @@
using GeometryTD.Procedure;
namespace GeometryTD.UI
{
public sealed class NodeItemContext : UIContext
{
public int NodeId;
public int SequenceIndex;
public RunNodeType NodeType;
public bool IsLocked;
public bool IsCurrent;
public bool IsCompleted;
public bool IsFailed;
public bool CanClick;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: da34e789554bd744e913db9fa3615322
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,11 @@
namespace GeometryTD.UI
{
public sealed class NodeMapFormContext : UIContext
{
public string Title;
public string ProgressText;
public string CurrentNodeText;
public bool IsRunCompleted;
public NodeItemContext[] NodeItems;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bb4720747caac9641b0bf06abbdad70f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,162 @@
using GeometryTD.CustomEvent;
using GeometryTD.Definition;
using GeometryTD.Procedure;
using GameFramework.Event;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace GeometryTD.UI
{
public sealed class NodeMapFormController : UIFormControllerCommonBase<NodeMapFormContext, NodeMapForm>
{
private NodeMapFormUseCase _useCase;
protected override UIFormType UIFormTypeId => UIFormType.NodeMapForm;
protected override void RefreshUI(NodeMapForm form, NodeMapFormContext context)
{
form.RefreshUI(context);
}
protected override void SubscribeCustomEvents()
{
GameEntry.Event.Subscribe(NodeMapNodeClickEventArgs.EventId, OnNodeClicked);
}
protected override void UnsubscribeCustomEvents()
{
GameEntry.Event.Unsubscribe(NodeMapNodeClickEventArgs.EventId, OnNodeClicked);
}
public override int? OpenUI(object userData = null)
{
if (userData is NodeMapFormContext context)
{
return OpenUIInternal(context);
}
if (userData is NodeMapFormRawData rawDataFromUserData)
{
return OpenUI(rawDataFromUserData);
}
if (userData != null)
{
Log.Warning("NodeMapFormController.OpenUI() userData type is invalid.");
return null;
}
if (_useCase == null)
{
Log.Error("NodeMapFormController.OpenUI() useCase is null.");
return null;
}
return OpenUI(_useCase.CreateInitialModel());
}
public int? OpenUI(NodeMapFormRawData rawData)
{
return OpenUIInternal(BuildContext(rawData));
}
public override void BindUseCase(IUIUseCase useCase)
{
if (!(useCase is NodeMapFormUseCase nodeMapFormUseCase))
{
Log.Error("NodeMapFormController.BindUseCase() useCase is invalid.");
return;
}
_useCase = nodeMapFormUseCase;
}
private void OnNodeClicked(object sender, GameEventArgs e)
{
if (!IsEventFromCurrentForm(sender) || !(e is NodeMapNodeClickEventArgs args) || _useCase == null)
{
return;
}
if (!_useCase.TryRequestEnterNode(args.SequenceIndex, out NodeMapNodeRawData selectedNode, out NodeMapFormRawData latestRawData))
{
if (latestRawData != null)
{
SetContext(BuildContext(latestRawData));
RefreshCurrentUI();
}
return;
}
if (latestRawData != null)
{
SetContext(BuildContext(latestRawData));
RefreshCurrentUI();
}
if (Form != null && selectedNode != null)
{
GameEntry.Event.Fire(Form, NodeMapNodeEnterRequestedEventArgs.Create(
selectedNode.RunId,
selectedNode.NodeId,
selectedNode.NodeType,
selectedNode.SequenceIndex));
}
}
private bool IsEventFromCurrentForm(object sender)
{
if (Form == null)
{
return false;
}
if (ReferenceEquals(sender, Form))
{
return true;
}
if (sender is Component component)
{
NodeMapForm ownerForm = component.GetComponentInParent<NodeMapForm>();
return ownerForm == Form;
}
return false;
}
private static NodeMapFormContext BuildContext(NodeMapFormRawData rawData)
{
NodeItemContext[] nodeItemContexts = System.Array.Empty<NodeItemContext>();
if (rawData?.Nodes != null && rawData.Nodes.Count > 0)
{
nodeItemContexts = new NodeItemContext[rawData.Nodes.Count];
for (int i = 0; i < rawData.Nodes.Count; i++)
{
NodeMapNodeRawData node = rawData.Nodes[i];
nodeItemContexts[i] = new NodeItemContext
{
NodeId = node?.NodeId ?? 0,
SequenceIndex = node?.SequenceIndex ?? i,
NodeType = node?.NodeType ?? RunNodeType.None,
IsLocked = node != null && node.Status == RunNodeStatus.Locked,
IsCurrent = node != null && node.IsCurrentNode,
IsCompleted = node != null && node.Status == RunNodeStatus.Completed,
IsFailed = node != null && node.Status == RunNodeStatus.Failed,
CanClick = node != null && node.CanEnter
};
}
}
return new NodeMapFormContext
{
Title = rawData?.Title ?? "节点地图",
ProgressText = rawData?.ProgressText ?? "0 / 0",
CurrentNodeText = rawData?.CurrentNodeText ?? "当前节点: 无",
IsRunCompleted = rawData != null && rawData.IsRunCompleted,
NodeItems = nodeItemContexts
};
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e24f8a016c2dd9b4b9e7aa34a24185a0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,28 @@
using System.Collections.Generic;
using GeometryTD.Procedure;
namespace GeometryTD.UI
{
public sealed class NodeMapFormRawData
{
public string RunId;
public string Title;
public string ProgressText;
public string CurrentNodeText;
public bool IsRunCompleted;
public List<NodeMapNodeRawData> Nodes;
}
public sealed class NodeMapNodeRawData
{
public string RunId;
public int NodeId;
public int SequenceIndex;
public RunNodeType NodeType;
public RunNodeStatus Status;
public bool IsCurrentNode;
public bool CanEnter;
public string Title;
public string StatusText;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 933dea9978c15484aab9df1bd8f32276
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,156 @@
using System.Collections.Generic;
using GeometryTD.Procedure;
namespace GeometryTD.UI
{
public sealed class NodeMapFormUseCase : IUIUseCase
{
private RunState _runState;
public void SetRunState(RunState runState)
{
_runState = runState;
}
public NodeMapFormRawData CreateInitialModel()
{
return BuildRawData(_runState);
}
public bool TryRequestEnterNode(int sequenceIndex, out NodeMapNodeRawData selectedNode, out NodeMapFormRawData latestRawData)
{
latestRawData = BuildRawData(_runState);
selectedNode = null;
if (_runState == null || _runState.IsCompleted)
{
return false;
}
RunNodeState currentNode = _runState.CurrentNode;
if (currentNode == null || currentNode.SequenceIndex != sequenceIndex || !_runState.CanEnterCurrentNode)
{
return false;
}
RunNodeState targetNode = _runState.GetNodeBySequenceIndex(sequenceIndex);
if (targetNode == null || targetNode.Status != RunNodeStatus.Available)
{
return false;
}
selectedNode = BuildNodeRawData(_runState.RunId, targetNode, currentNode.SequenceIndex);
return selectedNode != null && selectedNode.CanEnter;
}
private static NodeMapFormRawData BuildRawData(RunState runState)
{
if (runState == null)
{
return new NodeMapFormRawData
{
Title = "节点地图",
ProgressText = "0 / 0",
CurrentNodeText = "当前节点: 无",
IsRunCompleted = true,
Nodes = new List<NodeMapNodeRawData>()
};
}
List<NodeMapNodeRawData> nodes = new List<NodeMapNodeRawData>(runState.NodeCount);
int currentSequenceIndex = runState.CurrentNode != null ? runState.CurrentNode.SequenceIndex : -1;
foreach (RunNodeState node in runState.Nodes)
{
NodeMapNodeRawData nodeRawData = BuildNodeRawData(runState.RunId, node, currentSequenceIndex);
if (nodeRawData != null)
{
nodes.Add(nodeRawData);
}
}
string currentNodeText = runState.IsCompleted
? "当前节点: 已完成"
: $"当前节点: {BuildNodeTitle(runState.CurrentNode)}";
return new NodeMapFormRawData
{
RunId = runState.RunId,
Title = "节点地图",
ProgressText = $"{runState.CompletedNodeCount} / {runState.NodeCount}",
CurrentNodeText = currentNodeText,
IsRunCompleted = runState.IsCompleted,
Nodes = nodes
};
}
private static NodeMapNodeRawData BuildNodeRawData(string runId, RunNodeState node, int currentSequenceIndex)
{
if (node == null)
{
return null;
}
bool isCurrentNode = node.SequenceIndex == currentSequenceIndex;
bool canEnter = isCurrentNode && node.Status == RunNodeStatus.Available;
return new NodeMapNodeRawData
{
RunId = runId,
NodeId = node.NodeId,
SequenceIndex = node.SequenceIndex,
NodeType = node.NodeType,
Status = node.Status,
IsCurrentNode = isCurrentNode,
CanEnter = canEnter,
Title = BuildNodeTitle(node),
StatusText = BuildStatusText(node.Status, canEnter)
};
}
private static string BuildNodeTitle(RunNodeState node)
{
return node == null ? "未知节点" : BuildNodeTitle(node.NodeType);
}
private static string BuildNodeTitle(RunNodeType nodeType)
{
switch (nodeType)
{
case RunNodeType.Combat:
return "战斗";
case RunNodeType.Event:
return "事件";
case RunNodeType.Shop:
return "商店";
case RunNodeType.BossCombat:
return "Boss";
default:
return "未知节点";
}
}
private static string BuildStatusText(RunNodeStatus status, bool canEnter)
{
if (canEnter)
{
return "当前";
}
switch (status)
{
case RunNodeStatus.Locked:
return "未解锁";
case RunNodeStatus.Available:
return "可进入";
case RunNodeStatus.Completed:
return "已完成";
case RunNodeStatus.Failed:
return "失败";
case RunNodeStatus.Skipped:
return "跳过";
default:
return string.Empty;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e35c4c20ae9d48a4c8e9878e79b7d346
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,121 @@
using UnityEngine;
using UnityEngine.UI;
using GeometryTD.CustomEvent;
using GeometryTD.Procedure;
namespace GeometryTD.UI
{
public class NodeItem : MonoBehaviour
{
private const string CombatIconAssetName = "Combat";
private const string EventIconAssetName = "Event";
private const string ShopIconAssetName = "Shop";
private const string BossIconAssetName = "BossCombat";
[SerializeField] private Image _icon;
[SerializeField] private Image _bg;
[SerializeField] private CommonButton _button;
[SerializeField] private Color _lockedColor = Color.gray;
[SerializeField] private Color _activeColor = Color.cyan;
[SerializeField] private Color _passedColor = Color.green;
[SerializeField] private Color _failedColor = Color.red;
[SerializeField] private Color _defaultIconColor = Color.white;
[SerializeField] private Color _lockedIconColor = Color.gray;
private NodeItemContext _context;
private string _requestedIconAssetName;
public void RefreshUI(NodeItemContext context)
{
_context = context;
if (_button != null)
{
_button.Interactive = context != null && context.CanClick;
}
Color targetColor = _lockedColor;
if (context == null)
{
targetColor = _lockedColor;
}
else if (context.IsCompleted)
{
targetColor = _passedColor;
}
else if (context.IsFailed)
{
targetColor = _failedColor;
}
else if (context.IsCurrent)
{
targetColor = _activeColor;
}
if (_bg != null)
{
_bg.color = targetColor;
}
if (_icon != null)
{
RefreshIcon(context != null ? context.NodeType : RunNodeType.None);
_icon.color = context != null && !context.IsLocked ? _defaultIconColor : _lockedIconColor;
}
}
public void OnClick()
{
if (_context == null || !_context.CanClick)
{
return;
}
GameEntry.Event.Fire(this, NodeMapNodeClickEventArgs.Create(_context.SequenceIndex));
}
private void RefreshIcon(RunNodeType nodeType)
{
if (_icon == null)
{
return;
}
string assetName = ResolveIconAssetName(nodeType);
_requestedIconAssetName = assetName;
if (string.IsNullOrWhiteSpace(assetName) || GameEntry.SpriteCache == null)
{
_icon.sprite = null;
return;
}
GameEntry.SpriteCache.GetSprite(assetName, sprite =>
{
if (_icon == null || _requestedIconAssetName != assetName)
{
return;
}
_icon.sprite = sprite;
});
}
private static string ResolveIconAssetName(RunNodeType nodeType)
{
switch (nodeType)
{
case RunNodeType.Combat:
return CombatIconAssetName;
case RunNodeType.Event:
return EventIconAssetName;
case RunNodeType.Shop:
return ShopIconAssetName;
case RunNodeType.BossCombat:
return BossIconAssetName;
default:
return null;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d370c24f0bca1cd49b1163c3765e0f4c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,89 @@
using TMPro;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace GeometryTD.UI
{
public class NodeMapForm : UGuiForm
{
[SerializeField] private TMP_Text _titleText;
[SerializeField] private TMP_Text _progressText;
[SerializeField] private TMP_Text _currentNodeText;
[SerializeField] private NodeItem[] _nodeItems;
private NodeMapFormContext _context;
public void RefreshUI(NodeMapFormContext context)
{
_context = context;
if (_titleText != null)
{
_titleText.text = context?.Title ?? string.Empty;
}
if (_progressText != null)
{
_progressText.text = context?.ProgressText ?? string.Empty;
}
if (_currentNodeText != null)
{
_currentNodeText.text = context?.CurrentNodeText ?? string.Empty;
}
if (_nodeItems == null)
{
return;
}
for (int i = 0; i < _nodeItems.Length; i++)
{
NodeItemContext itemContext =
context?.NodeItems != null && i < context.NodeItems.Length ? context.NodeItems[i] : null;
_nodeItems[i]?.RefreshUI(itemContext);
}
}
protected override void OnOpen(object userData)
{
base.OnOpen(userData);
if (userData is NodeMapFormContext context)
{
RefreshUI(context);
return;
}
Log.Warning("NodeMapForm requires NodeMapFormContext as userData.");
}
protected override void OnClose(bool isShutdown, object userData)
{
_context = null;
if (_titleText != null)
{
_titleText.text = string.Empty;
}
if (_progressText != null)
{
_progressText.text = string.Empty;
}
if (_currentNodeText != null)
{
_currentNodeText.text = string.Empty;
}
if (_nodeItems != null)
{
for (int i = 0; i < _nodeItems.Length; i++)
{
_nodeItems[i]?.RefreshUI(null);
}
}
base.OnClose(isShutdown, userData);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 16f09225744e9ed45ba3ed24c27f9602
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,13 @@
namespace GeometryTD.UI
{
public class MenuFormContext : UIContext
{
public string TitleText { get; set; }
public string StartButtonText { get; set; }
public string SettingsButtonText { get; set; }
public string ExitButtonText { get; set; }
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8b608c268739c144990195981f1c4465
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,6 +1,9 @@
using GeometryTD.Procedure;
namespace GeometryTD.UI namespace GeometryTD.UI
{ {
public class TestMenuFormContext : UIContext public class TestMenuFormContext : UIContext
{ {
public RunNodeType CurrentNodeType { get; set; }
} }
} }

View File

@ -0,0 +1,129 @@
using GeometryTD.CustomEvent;
using GeometryTD.Definition;
using GeometryTD.Procedure;
using GameFramework.Event;
using UnityGameFramework.Runtime;
namespace GeometryTD.UI
{
public class MenuFormController : UIFormControllerCommonBase<MenuFormContext, MenuForm>
{
private MenuFormUseCase _useCase;
protected override UIFormType UIFormTypeId => UIFormType.MenuForm;
protected override void RefreshUI(MenuForm form, MenuFormContext context)
{
form.RefreshUI(context);
}
protected override void SubscribeCustomEvents()
{
GameEntry.Event.Subscribe(MenuStartRequestedEventArgs.EventId, OnStartRequested);
GameEntry.Event.Subscribe(MenuSettingsRequestedEventArgs.EventId, OnSettingsRequested);
GameEntry.Event.Subscribe(MenuExitRequestedEventArgs.EventId, OnExitRequested);
}
protected override void UnsubscribeCustomEvents()
{
GameEntry.Event.Unsubscribe(MenuStartRequestedEventArgs.EventId, OnStartRequested);
GameEntry.Event.Unsubscribe(MenuSettingsRequestedEventArgs.EventId, OnSettingsRequested);
GameEntry.Event.Unsubscribe(MenuExitRequestedEventArgs.EventId, OnExitRequested);
}
public override int? OpenUI(object userData = null)
{
if (userData is MenuFormContext context)
{
return OpenUIInternal(context);
}
if (userData is MenuFormRawData rawDataFromUserData)
{
return OpenUI(rawDataFromUserData);
}
if (userData != null)
{
Log.Warning("MenuFormController.OpenUI() userData type is invalid.");
return null;
}
if (_useCase == null)
{
Log.Error("MenuFormController.OpenUI() useCase is null.");
return null;
}
return OpenUI(_useCase.CreateInitialModel());
}
public int? OpenUI(MenuFormRawData rawData)
{
return OpenUIInternal(BuildContext(rawData));
}
public override void BindUseCase(IUIUseCase useCase)
{
if (!(useCase is MenuFormUseCase menuFormUseCase))
{
Log.Error("MenuFormController.BindUseCase() useCase is invalid.");
return;
}
_useCase = menuFormUseCase;
}
private void OnStartRequested(object sender, GameEventArgs e)
{
if (!IsCurrentFormEvent(sender) || !(e is MenuStartRequestedEventArgs))
{
return;
}
if (GameEntry.Procedure.CurrentProcedure is ProcedureMenu procedureMenu)
{
procedureMenu.GameStart = true;
return;
}
Log.Warning("MenuFormController received start request outside ProcedureMenu.");
}
private void OnSettingsRequested(object sender, GameEventArgs e)
{
if (!IsCurrentFormEvent(sender) || !(e is MenuSettingsRequestedEventArgs))
{
return;
}
Log.Warning("Menu settings button click is TODO.");
}
private void OnExitRequested(object sender, GameEventArgs e)
{
if (!IsCurrentFormEvent(sender) || !(e is MenuExitRequestedEventArgs))
{
return;
}
UnityGameFramework.Runtime.GameEntry.Shutdown(ShutdownType.Quit);
}
private bool IsCurrentFormEvent(object sender)
{
return Form != null && ReferenceEquals(sender, Form);
}
private static MenuFormContext BuildContext(MenuFormRawData rawData)
{
return new MenuFormContext
{
TitleText = rawData?.TitleText ?? string.Empty,
StartButtonText = rawData?.StartButtonText ?? string.Empty,
SettingsButtonText = rawData?.SettingsButtonText ?? string.Empty,
ExitButtonText = rawData?.ExitButtonText ?? string.Empty
};
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3ec06b97e6bc9d743a6340377ab7cd8b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,6 +1,6 @@
using GeometryTD.CustomEvent; using GeometryTD.CustomEvent;
using GeometryTD.Definition; using GeometryTD.Definition;
using GameFramework.Event; using GeometryTD.Procedure;
using UnityGameFramework.Runtime; using UnityGameFramework.Runtime;
namespace GeometryTD.UI namespace GeometryTD.UI
@ -16,12 +16,10 @@ namespace GeometryTD.UI
protected override void SubscribeCustomEvents() protected override void SubscribeCustomEvents()
{ {
GameEntry.Event.Subscribe(TestMenuNodeClickEventArgs.EventId, OnNodeClick);
} }
protected override void UnsubscribeCustomEvents() protected override void UnsubscribeCustomEvents()
{ {
GameEntry.Event.Unsubscribe(TestMenuNodeClickEventArgs.EventId, OnNodeClick);
} }
public override int? OpenUI(object userData = null) public override int? OpenUI(object userData = null)
@ -50,36 +48,10 @@ namespace GeometryTD.UI
private static TestMenuFormContext BuildDefaultContext() private static TestMenuFormContext BuildDefaultContext()
{ {
return new TestMenuFormContext(); return new TestMenuFormContext
{
CurrentNodeType = RunNodeType.None
};
} }
private void OnNodeClick(object sender, GameEventArgs e)
{
if (!(sender is TestMenuForm form))
{
return;
}
if (!(e is TestMenuNodeClickEventArgs args))
{
return;
}
switch (args.NodeType)
{
case TestMenuNodeType.Combat:
GameEntry.CombatNode.StartCombat();
return;
case TestMenuNodeType.Event:
GameEntry.EventNode.StartEvent();
return;
case TestMenuNodeType.Shop:
GameEntry.ShopNode.StartShop();
return;
default:
return;
}
}
} }
} }

View File

@ -0,0 +1,13 @@
namespace GeometryTD.UI
{
public class MenuFormRawData
{
public string TitleText { get; set; }
public string StartButtonText { get; set; }
public string SettingsButtonText { get; set; }
public string ExitButtonText { get; set; }
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5dc8f63e892ff6745aed855ae42cfd88
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,16 @@
namespace GeometryTD.UI
{
public class MenuFormUseCase : IUIUseCase
{
public MenuFormRawData CreateInitialModel()
{
return new MenuFormRawData
{
TitleText = "GeometryTD",
StartButtonText = "Start",
SettingsButtonText = "Settings",
ExitButtonText = "Exit"
};
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1fc5bfbd1fcf533448f2669b0eda64bf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,76 @@
using GeometryTD.CustomEvent;
using TMPro;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace GeometryTD.UI
{
public class MenuForm : UGuiForm
{
[SerializeField] private TMP_Text _titleText;
[SerializeField] private TMP_Text _startButtonText;
[SerializeField] private TMP_Text _settingsButtonText;
[SerializeField] private TMP_Text _exitButtonText;
private MenuFormContext _context;
public void RefreshUI(MenuFormContext context)
{
_context = context;
if (_context == null)
{
return;
}
SetText(_titleText, _context.TitleText);
SetText(_startButtonText, _context.StartButtonText);
SetText(_settingsButtonText, _context.SettingsButtonText);
SetText(_exitButtonText, _context.ExitButtonText);
}
public void OnStartButtonClick()
{
GameEntry.Event.Fire(this, MenuStartRequestedEventArgs.Create());
}
public void OnSettingsButtonClick()
{
GameEntry.Event.Fire(this, MenuSettingsRequestedEventArgs.Create());
}
public void OnExitButtonClick()
{
GameEntry.Event.Fire(this, MenuExitRequestedEventArgs.Create());
}
protected override void OnOpen(object userData)
{
base.OnOpen(userData);
if (userData is MenuFormContext context)
{
RefreshUI(context);
return;
}
Log.Warning("MenuForm requires MenuFormContext as userData.");
}
protected override void OnClose(bool isShutdown, object userData)
{
_context = null;
base.OnClose(isShutdown, userData);
}
private static void SetText(TMP_Text textComponent, string value)
{
if (textComponent == null)
{
return;
}
textComponent.text = value ?? string.Empty;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fdf317aa70fe94f44a332b6ee6ef5bbc
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,10 +1,16 @@
using GeometryTD.CustomEvent; using GeometryTD.CustomEvent;
using GeometryTD.Procedure;
using UnityEngine;
using UnityGameFramework.Runtime; using UnityGameFramework.Runtime;
namespace GeometryTD.UI namespace GeometryTD.UI
{ {
public class TestMenuForm : UGuiForm public class TestMenuForm : UGuiForm
{ {
[SerializeField] private GameObject combatButtonObject;
[SerializeField] private GameObject eventButtonObject;
[SerializeField] private GameObject shopButtonObject;
private TestMenuFormContext _context; private TestMenuFormContext _context;
public void RefreshUI(TestMenuFormContext context) public void RefreshUI(TestMenuFormContext context)
@ -12,8 +18,17 @@ namespace GeometryTD.UI
_context = context; _context = context;
if (_context == null) if (_context == null)
{ {
SetButtonVisible(combatButtonObject, false);
SetButtonVisible(eventButtonObject, false);
SetButtonVisible(shopButtonObject, false);
return; return;
} }
SetButtonVisible(
combatButtonObject,
_context.CurrentNodeType == RunNodeType.Combat || _context.CurrentNodeType == RunNodeType.BossCombat);
SetButtonVisible(eventButtonObject, _context.CurrentNodeType == RunNodeType.Event);
SetButtonVisible(shopButtonObject, _context.CurrentNodeType == RunNodeType.Shop);
} }
public void OnCombatButtonClick() public void OnCombatButtonClick()
@ -47,8 +62,19 @@ namespace GeometryTD.UI
protected override void OnClose(bool isShutdown, object userData) protected override void OnClose(bool isShutdown, object userData)
{ {
_context = null; _context = null;
SetButtonVisible(combatButtonObject, false);
SetButtonVisible(eventButtonObject, false);
SetButtonVisible(shopButtonObject, false);
base.OnClose(isShutdown, userData); base.OnClose(isShutdown, userData);
} }
private static void SetButtonVisible(GameObject buttonObject, bool visible)
{
if (buttonObject != null)
{
buttonObject.SetActive(visible);
}
}
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -0,0 +1,127 @@
fileFormatVersion: 2
guid: c40f3ef20f4b7934aad143765274d7bb
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

View File

@ -0,0 +1,127 @@
fileFormatVersion: 2
guid: 34b43696f3cbf38409bb2d040e96ee86
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

View File

@ -0,0 +1,127 @@
fileFormatVersion: 2
guid: 048acf1176eaa5f48a12485e8991aa96
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,127 @@
fileFormatVersion: 2
guid: cdef6ec8b51831a4abf9688dde8e2281
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 13
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
flipGreenChannel: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMipmapLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
swizzle: 50462976
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
ignorePlatformSupport: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
mipmapLimitGroupName:
pSDRemoveMatte: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,720 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1485660147845521821
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3442204668286505931}
- component: {fileID: 7247274277813398792}
- component: {fileID: 5832248750743189576}
m_Layer: 5
m_Name: Title
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &3442204668286505931
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1485660147845521821}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 3471644370828071279}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 450}
m_SizeDelta: {x: 1000, y: 200}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &7247274277813398792
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1485660147845521821}
m_CullTransparentMesh: 1
--- !u!114 &5832248750743189576
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1485660147845521821}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: Geometry
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 100
m_fontSizeBase: 100
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 1
m_HorizontalAlignment: 2
m_VerticalAlignment: 512
m_textAlignment: 65535
m_characterSpacing: 0
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_enableWordWrapping: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 1
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
m_hasFontAssetChanged: 0
m_baseMaterial: {fileID: 0}
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
--- !u!1 &6351599272186829672
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3471644370828071279}
- component: {fileID: 1596541747939020788}
m_Layer: 5
m_Name: MenuForm
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &3471644370828071279
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6351599272186829672}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 3442204668286505931}
- {fileID: 2124736747478720832}
- {fileID: 8167974608901112604}
- {fileID: 7693594745400141304}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1596541747939020788
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6351599272186829672}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fdf317aa70fe94f44a332b6ee6ef5bbc, type: 3}
m_Name:
m_EditorClassIdentifier:
_titleText: {fileID: 5832248750743189576}
_startButtonText: {fileID: 4147629153443456746}
_settingsButtonText: {fileID: 6172671250818335926}
_exitButtonText: {fileID: 5635940221953385042}
--- !u!1001 &2533297389376661431
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 3471644370828071279}
m_Modifications:
- target: {fileID: 770565994539545022, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_Name
value: StartButton
objectReference: {fileID: 0}
- target: {fileID: 1920576543566152029, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_text
value: "\u5F00\u59CB\u6E38\u620F"
objectReference: {fileID: 0}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_Mode
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[0].m_Target
value:
objectReference: {fileID: 1596541747939020788}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_Target
value:
objectReference: {fileID: 1596541747939020788}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onHover.m_PersistentCalls.m_Calls.Array.data[0].m_Target
value:
objectReference: {fileID: 1596541747939020788}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName
value: OnStartButtonClick
objectReference: {fileID: 0}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName
value: GeometryTD.UI.MenuForm, Assembly-CSharp
objectReference: {fileID: 0}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_Arguments.m_ObjectArgumentAssemblyTypeName
value: UnityEngine.Object, UnityEngine
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMax.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMax.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMin.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMin.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_SizeDelta.x
value: 400
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_SizeDelta.y
value: 80
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 150
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 2307f223279813546a43b221ddd496cc, type: 3}
--- !u!224 &2124736747478720832 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
m_PrefabInstance: {fileID: 2533297389376661431}
m_PrefabAsset: {fileID: 0}
--- !u!114 &4147629153443456746 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 1920576543566152029, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
m_PrefabInstance: {fileID: 2533297389376661431}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1001 &5696765442475836907
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 3471644370828071279}
m_Modifications:
- target: {fileID: 770565994539545022, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_Name
value: SettingsButton
objectReference: {fileID: 0}
- target: {fileID: 1920576543566152029, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_text
value: "\u6E38\u620F\u8BBE\u7F6E"
objectReference: {fileID: 0}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_Mode
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[0].m_Target
value:
objectReference: {fileID: 1596541747939020788}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_Target
value:
objectReference: {fileID: 1596541747939020788}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onHover.m_PersistentCalls.m_Calls.Array.data[0].m_Target
value:
objectReference: {fileID: 1596541747939020788}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName
value: OnSettingsButtonClick
objectReference: {fileID: 0}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName
value: GeometryTD.UI.MenuForm, Assembly-CSharp
objectReference: {fileID: 0}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_Arguments.m_ObjectArgumentAssemblyTypeName
value: UnityEngine.Object, UnityEngine
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMax.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMax.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMin.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMin.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_SizeDelta.x
value: 400
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_SizeDelta.y
value: 80
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 2307f223279813546a43b221ddd496cc, type: 3}
--- !u!114 &6172671250818335926 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 1920576543566152029, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
m_PrefabInstance: {fileID: 5696765442475836907}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!224 &8167974608901112604 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
m_PrefabInstance: {fileID: 5696765442475836907}
m_PrefabAsset: {fileID: 0}
--- !u!1001 &6093832046355637007
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 3471644370828071279}
m_Modifications:
- target: {fileID: 770565994539545022, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_Name
value: ExitButton
objectReference: {fileID: 0}
- target: {fileID: 1920576543566152029, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_text
value: "\u9000\u51FA\u6E38\u620F"
objectReference: {fileID: 0}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_Mode
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[0].m_Target
value:
objectReference: {fileID: 1596541747939020788}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_Target
value:
objectReference: {fileID: 1596541747939020788}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onHover.m_PersistentCalls.m_Calls.Array.data[0].m_Target
value:
objectReference: {fileID: 1596541747939020788}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName
value: OnExitButtonClick
objectReference: {fileID: 0}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName
value: GeometryTD.UI.MenuForm, Assembly-CSharp
objectReference: {fileID: 0}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_Arguments.m_ObjectArgumentAssemblyTypeName
value: UnityEngine.Object, UnityEngine
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMax.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMax.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMin.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMin.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_SizeDelta.x
value: 400
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_SizeDelta.y
value: 80
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchoredPosition.y
value: -150
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 2307f223279813546a43b221ddd496cc, type: 3}
--- !u!114 &5635940221953385042 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 1920576543566152029, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
m_PrefabInstance: {fileID: 6093832046355637007}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!224 &7693594745400141304 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
m_PrefabInstance: {fileID: 6093832046355637007}
m_PrefabAsset: {fileID: 0}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9307a2d7191791348b6eaef1fbebf4cf
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c97f2161a8ca2064ca526daab5af3c12
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -49,6 +49,9 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: d1cfd203143c34c4e853705bdc409e04, type: 3} m_Script: {fileID: 11500000, guid: d1cfd203143c34c4e853705bdc409e04, type: 3}
m_Name: m_Name:
m_EditorClassIdentifier: m_EditorClassIdentifier:
combatButtonObject: {fileID: 4510397703366314199}
eventButtonObject: {fileID: 6875912589832396601}
shopButtonObject: {fileID: 8107616822249026203}
--- !u!1 &6790072542047644883 --- !u!1 &6790072542047644883
GameObject: GameObject:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -353,6 +356,12 @@ RectTransform:
type: 3} type: 3}
m_PrefabInstance: {fileID: 3758745783397349737} m_PrefabInstance: {fileID: 3758745783397349737}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
--- !u!1 &4510397703366314199 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 770565994539545022, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
m_PrefabInstance: {fileID: 3758745783397349737}
m_PrefabAsset: {fileID: 0}
--- !u!1001 &6187312163487411847 --- !u!1001 &6187312163487411847
PrefabInstance: PrefabInstance:
m_ObjectHideFlags: 0 m_ObjectHideFlags: 0
@ -586,6 +595,12 @@ PrefabInstance:
m_AddedGameObjects: [] m_AddedGameObjects: []
m_AddedComponents: [] m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 2307f223279813546a43b221ddd496cc, type: 3} m_SourcePrefab: {fileID: 100100000, guid: 2307f223279813546a43b221ddd496cc, type: 3}
--- !u!1 &6875912589832396601 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 770565994539545022, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
m_PrefabInstance: {fileID: 6187312163487411847}
m_PrefabAsset: {fileID: 0}
--- !u!224 &7748794988612724848 stripped --- !u!224 &7748794988612724848 stripped
RectTransform: RectTransform:
m_CorrespondingSourceObject: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc, m_CorrespondingSourceObject: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
@ -831,3 +846,9 @@ RectTransform:
type: 3} type: 3}
m_PrefabInstance: {fileID: 8806106529173603109} m_PrefabInstance: {fileID: 8806106529173603109}
m_PrefabAsset: {fileID: 0} m_PrefabAsset: {fileID: 0}
--- !u!1 &8107616822249026203 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 770565994539545022, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
m_PrefabInstance: {fileID: 8806106529173603109}
m_PrefabAsset: {fileID: 0}

View File

@ -0,0 +1,330 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1139814490629641939
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8769328334771685493}
- component: {fileID: 2051869934177668487}
- component: {fileID: 1866624916103966737}
m_Layer: 5
m_Name: NodeItem
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &8769328334771685493
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1139814490629641939}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 9221979297406254555}
- {fileID: 1404818474728967281}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: -1200, y: 180}
m_SizeDelta: {x: 100, y: 100}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &2051869934177668487
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1139814490629641939}
m_CullTransparentMesh: 1
--- !u!114 &1866624916103966737
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1139814490629641939}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d370c24f0bca1cd49b1163c3765e0f4c, type: 3}
m_Name:
m_EditorClassIdentifier:
_icon: {fileID: 5671637636532677122}
_bg: {fileID: 5994609020701889777}
_button: {fileID: 8781361341733077650}
_lockedColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
_activeColor: {r: 0, g: 1, b: 1, a: 1}
_passedColor: {r: 0, g: 1, b: 0, a: 1}
_failedColor: {r: 1, g: 0, b: 0, a: 1}
_defaultIconColor: {r: 1, g: 1, b: 1, a: 1}
_lockedIconColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
--- !u!1 &4536174452495825529
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1404818474728967281}
- component: {fileID: 1379735801209342601}
- component: {fileID: 5671637636532677122}
m_Layer: 5
m_Name: icon
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!224 &1404818474728967281
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4536174452495825529}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8769328334771685493}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 1, y: 1}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 0, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!222 &1379735801209342601
CanvasRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4536174452495825529}
m_CullTransparentMesh: 1
--- !u!114 &5671637636532677122
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4536174452495825529}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 0.6039216, b: 0.5176471, a: 1}
m_RaycastTarget: 0
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: 56b8df63bbad60749a69e38bc687fadf, type: 3}
m_Type: 0
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4
m_FillAmount: 1
m_FillClockwise: 1
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1001 &4733156844748389164
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 8769328334771685493}
m_Modifications:
- target: {fileID: 770565994539545022, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_Name
value: CommonButton
objectReference: {fileID: 0}
- target: {fileID: 1341699087252484061, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_Sprite
value:
objectReference: {fileID: 21300000, guid: 9f847ec5e66e03e4ead1d3c5f7b510e8,
type: 3}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_Mode
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_Target
value:
objectReference: {fileID: 1866624916103966737}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName
value: OnClick
objectReference: {fileID: 0}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName
value: GeometryTD.UI.NodeItem, Assembly-CSharp
objectReference: {fileID: 0}
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_Arguments.m_ObjectArgumentAssemblyTypeName
value: UnityEngine.Object, UnityEngine
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_Pivot.x
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_Pivot.y
value: 0.5
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMax.x
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMax.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMin.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchorMin.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_SizeDelta.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_SizeDelta.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchoredPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 7888786393168201163, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
propertyPath: m_Name
value: bg
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects:
- {fileID: 7607456171798064113, guid: 2307f223279813546a43b221ddd496cc, type: 3}
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 2307f223279813546a43b221ddd496cc, type: 3}
--- !u!114 &5994609020701889777 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 1341699087252484061, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
m_PrefabInstance: {fileID: 4733156844748389164}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!114 &8781361341733077650 stripped
MonoBehaviour:
m_CorrespondingSourceObject: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
m_PrefabInstance: {fileID: 4733156844748389164}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a5079836f95c2a44b96fa331487ebb70, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!224 &9221979297406254555 stripped
RectTransform:
m_CorrespondingSourceObject: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
type: 3}
m_PrefabInstance: {fileID: 4733156844748389164}
m_PrefabAsset: {fileID: 0}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 94e1f0fbe373d4649aa3cb6748d9e95e
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -348,7 +348,7 @@ PrefabInstance:
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3} - target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
propertyPath: m_AvailableProcedureTypeNames.Array.size propertyPath: m_AvailableProcedureTypeNames.Array.size
value: 12 value: 13
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3} - target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
propertyPath: m_AvailableProcedureTypeNames.Array.data[0] propertyPath: m_AvailableProcedureTypeNames.Array.data[0]
@ -372,35 +372,35 @@ PrefabInstance:
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3} - target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
propertyPath: m_AvailableProcedureTypeNames.Array.data[5] propertyPath: m_AvailableProcedureTypeNames.Array.data[5]
value: GeometryTD.Procedure.ProcedureMenu value: GeometryTD.Procedure.ProcedureMain
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3} - target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
propertyPath: m_AvailableProcedureTypeNames.Array.data[6] propertyPath: m_AvailableProcedureTypeNames.Array.data[6]
value: GeometryTD.Procedure.ProcedurePreload value: GeometryTD.Procedure.ProcedureMenu
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3} - target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
propertyPath: m_AvailableProcedureTypeNames.Array.data[7] propertyPath: m_AvailableProcedureTypeNames.Array.data[7]
value: GeometryTD.Procedure.ProcedureSplash value: GeometryTD.Procedure.ProcedurePreload
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3} - target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
propertyPath: m_AvailableProcedureTypeNames.Array.data[8] propertyPath: m_AvailableProcedureTypeNames.Array.data[8]
value: GeometryTD.Procedure.ProcedureTest value: GeometryTD.Procedure.ProcedureSplash
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3} - target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
propertyPath: m_AvailableProcedureTypeNames.Array.data[9] propertyPath: m_AvailableProcedureTypeNames.Array.data[9]
value: GeometryTD.Procedure.ProcedureUpdateResources value: GeometryTD.Procedure.ProcedureTest
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3} - target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
propertyPath: m_AvailableProcedureTypeNames.Array.data[10] propertyPath: m_AvailableProcedureTypeNames.Array.data[10]
value: GeometryTD.Procedure.ProcedureUpdateVersion value: GeometryTD.Procedure.ProcedureUpdateResources
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3} - target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
propertyPath: m_AvailableProcedureTypeNames.Array.data[11] propertyPath: m_AvailableProcedureTypeNames.Array.data[11]
value: GeometryTD.Procedure.ProcedureVerifyResources value: GeometryTD.Procedure.ProcedureUpdateVersion
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3} - target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
propertyPath: m_AvailableProcedureTypeNames.Array.data[12] propertyPath: m_AvailableProcedureTypeNames.Array.data[12]
value: Procedure.ProcedureVerifyResources value: GeometryTD.Procedure.ProcedureVerifyResources
objectReference: {fileID: 0} objectReference: {fileID: 0}
- target: {fileID: 11413340, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3} - target: {fileID: 11413340, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
propertyPath: m_AudioMixer propertyPath: m_AudioMixer

View File

@ -1,39 +1,37 @@
# CodeX TODO # CodeX TODO
最后更新2026-03-07 最后更新2026-03-08
## 当前目标 ## 当前目标
`docs/TODO.md` 的 M1 现状推进最小可玩闭环。当前代码已经具备: `docs/TODO.md` 的 M1 目标推进最小可玩闭环,并以“能从开始游戏一路推进到 Boss 结算”为准检查当前实现。
- 基础战斗节点玩法
- 事件节点基础占位
- 仓库/组装 UI 骨架
- 局内掉落与战斗结算的一部分
但离“可从开始游戏一路完成一个大关”的 M1 验收还有明显缺口。后续重点是: 和上一版相比,仓库已经把 Run 相关基础件进一步接到了 `ProcedureMain`,因此这份清单不再把重点放在“有没有 Run 模型”,而是聚焦下面这几个真实阻塞项:
- 补真正的单局 Run 流程,而不是继续依赖 `TestMenuForm` 手动点节点。
- 把 10 节点固定大关、节点推进、Boss 终点串成闭环。
- 把组装、品质、Tag、耐久从“有数据结构/有 UI”补成“实际影响战斗结果”的规则闭环。
- 补商店节点真实实现,否则 M1 主流程无法跑通。
## 已完成 - 已有 `ProcedureMain + TestMenuForm` 的临时 Run 推进闭环,但还没有正式节点地图 / 节点面板。
- 固定 10 节点顺序已经开始驱动战斗 / 事件 / 商店入口,但节点事件上下文仍然是空载版本。
- 出战入口已有“至少有参战塔”的最小校验,但还没收口成严格的最终合法性约束。
- 品质 / Tag / 耐久仍然停留在部分实现状态,尚未和 M1 范围完全对齐。
## 当前已完成
### 1. 战斗主链路已经能独立跑通一场 ### 1. 战斗主链路已经能独立跑通一场
- `CombatNodeComponent` 能加载关卡、阶段和出怪表,并启动 `CombatScheduler`
- `CombatScheduler` 已经具备加载地图、推进 phase、结算与返回的基础流程。 - `CombatNodeComponent` 能加载关卡、阶段、出怪表并启动 `CombatScheduler`
- 战斗内已有基地血量、建塔花费、敌人到家扣血、胜负结束等基础逻辑。 - `CombatScheduler` 已具备加载地图、推进 phase、结算、失败返回等基础流程。
- 战斗内已有基地血量、建塔消耗、敌人到家扣血、胜负结束等基础规则。
关键文件: 关键文件:
- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatNodeComponent.cs` - `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatNodeComponent.cs`
- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatScheduler.cs` - `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatScheduler.cs`
- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/` - `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatStates/`
- `Assets/GameMain/Scripts/Entity/EntityLogic/MapEntity.cs` - `Assets/GameMain/Scripts/Entity/EntityLogic/MapEntity.cs`
- `Assets/GameMain/Scripts/Scene/Map/`
### 2. 战斗结算、掉落与奖励选择已有基础实现 ### 2. 战斗结算、掉落与奖励选择已有基础实现
- 战斗内敌人被击败后,已能发放 coin / gold / 组件掉落。
- `CombatInRunResourceManager` 已维护本场奖励背包快照。 - 敌人被击败后已能发放 coin / gold / 组件掉落。
- 结算链已经包含奖励计算、奖励选择 UI、FinishForm 返回等基础骨架。 - `CombatInRunResourceManager` 维护局内资源与奖励背包快照。
- 结算链已包含奖励计算、奖励选择 UI、FinishForm 返回等基础骨架。
关键文件: 关键文件:
- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatInRunResourceManager.cs` - `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatInRunResourceManager.cs`
@ -41,11 +39,12 @@
- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatSettlementFlowService.cs` - `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatSettlementFlowService.cs`
- `Assets/GameMain/Scripts/UI/Combat/` - `Assets/GameMain/Scripts/UI/Combat/`
### 3. 背包与组装基础能力已经存在 ### 3. 背包、参战区与组装基础能力已经存在
- `PlayerInventoryComponent` 已有库存快照、金币读写、参战塔名单、组装塔入口。
- `PlayerInventoryComponent` 已支持库存快照、金币读写、参战塔名单、组装塔入口。
- `RepoForm` 已能展示组件、塔、参战区和组装区。 - `RepoForm` 已能展示组件、塔、参战区和组装区。
- `CombineArea` 已有三槽约束,只有枪口/轴承/底座齐备时才会发起组合请求。 - `CombineArea` 已有三槽约束,只有枪口 / 轴承 / 底座齐备时才会发起组合请求。
- `PlayerInventoryTowerAssemblyService` 已能基于三组件生成 `TowerItemData` `TowerStatsData` - `PlayerInventoryTowerAssemblyService` 已能基于三组件生成 `TowerItemData` `TowerStatsData`
关键文件: 关键文件:
- `Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryComponent.cs` - `Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryComponent.cs`
@ -54,70 +53,110 @@
- `Assets/GameMain/Scripts/UI/Game/View/CombineArea.cs` - `Assets/GameMain/Scripts/UI/Game/View/CombineArea.cs`
- `Assets/GameMain/Scripts/UI/Game/Controller/RepoFormController.cs` - `Assets/GameMain/Scripts/UI/Game/Controller/RepoFormController.cs`
### 4. 事件节点有基础占位实现 ### 4. 事件节点已有可进入、可结算的基础实现
- `EventNodeComponent` 已能读取 `Event.txt`,解析事件选项并随机打开一个事件。
- 事件完成后会发出 `NodeCompleteEventArgs` 返回上层流程。 - `EventNodeComponent` 能读取 `Event.txt`,解析事件选项并随机打开事件。
- `EventForm` 的打开 / 关闭现已统一走 `UIRouter`,不再混用私有 controller。
- 事件完成后会关闭 UI 并发出 `NodeCompleteEventArgs`
关键文件: 关键文件:
- `Assets/GameMain/Scripts/CustomComponent/EventNodeComponent.cs` - `Assets/GameMain/Scripts/CustomComponent/EventNodeComponent.cs`
- `Assets/GameMain/Scripts/UI/Game/UseCase/EventFormUseCase.cs` - `Assets/GameMain/Scripts/UI/Game/UseCase/EventFormUseCase.cs`
- `Assets/GameMain/Scripts/UI/Game/Controller/EventFormController.cs` - `Assets/GameMain/Scripts/UI/Game/Controller/EventFormController.cs`
## 还没完成 ### 5. Run 模型和 10 节点固定序列已经落地到代码与测试
### 1. M1 真正的 Run 流程还不存在 - 已有 `RunNodeType / RunNodeStatus / RunState / RunNodeState` 等运行时模型。
- 当前入口仍是 `ProcedureMenu` 里打开 `MainForm + TestMenuForm` - 已有 `RunStateFactory``RunStateAdvanceService` 处理节点创建、推进、失败和完成。
- 玩家目前是手动点击 `战斗 / 事件 / 商店` 按钮进入节点,不是通过单局大关顺序推进。 - 已有 `FixedRunNodeSequenceBuilder`Plain 主题下固定生成 10 节点,并且第 10 节点是 `BossCombat`
- 代码里没有明确的“当前节点 / 节点列表 / 节点索引 / 大关完成”运行时模型。 - 已有 Editor 测试覆盖 `RunState` 创建、节点推进、Boss 节点和固定 10 节点序列。
- `docs/TODO.md``P0-04 / P0-05 / P0-06` 从验收标准看都还没有完整落地。
直接证据:
- `ProcedureMenu` 进入后直接打开测试菜单。
- `TestMenuFormController` 直接转发到 `StartCombat / StartEvent / StartShop`
关键文件: 关键文件:
- `Assets/GameMain/Scripts/Procedure/ProcedureMenu.cs` - `Assets/GameMain/Scripts/Procedure/RunModel.cs`
- `Assets/GameMain/Scripts/UI/Menu/Controller/TestMenuFormController.cs` - `Assets/GameMain/Scripts/Procedure/RunStateFactory.cs`
- `Assets/GameMain/Scripts/Procedure/RunStateAdvanceService.cs`
- `Assets/GameMain/Scripts/Procedure/FixedRunNodeSequenceBuilder.cs`
- `Assets/GameMain/Tests/Editor/RunStateTests.cs`
### 2. 10 节点地图生成与 Boss 终点未实现 ### 6. 商店节点已经有最小可用实现
- 当前没有发现“固定 10 节点”或“第 10 节点固定 Boss”的节点生成器。
- `CombatNodeComponent.StartCombat()` 仍是从当前主题关卡池里随机抽一个 `DRLevel` 开战。
- 现有 Boss 相关逻辑只存在于战斗内部的 `EntryType.Boss / BossDead`,不是大关节点层面的第 10 节点约束。
关键文件: - `ShopNodeComponent.StartShop()` 已不再是空方法。
- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatNodeComponent.cs` - 新版 `ShopFormUseCase` 已能随机生成 4 个组件商品。
- `Assets/GameMain/Scripts/CustomComponent/CombatNode/EnemyManager/EnemySpawnDirector.cs` - 已支持购买、扣金、把组件写回 `PlayerInventory`、退出商店。
- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/PhaseEndConditions/BossDeadPhaseEndCondition.cs`
### 3. 商店节点基本未实现,当前是主流程硬缺口
- `ShopNodeComponent.StartShop()` 仍然是空方法。
- 旧版 `ShopFormUseCase / ShopFormController / ShopForm` 基本都是整文件注释状态,不能视为可用实现。
- 因此 `战斗 -> 事件 -> 商店 -> 组装 -> 下一节点` 这条 M1 主链路实际上卡在商店节点。
关键文件: 关键文件:
- `Assets/GameMain/Scripts/CustomComponent/ShopNodeComponent.cs` - `Assets/GameMain/Scripts/CustomComponent/ShopNodeComponent.cs`
- `Assets/GameMain/Scripts/UI/Templates/GameScene/UseCase/ShopFormUseCase.cs` - `Assets/GameMain/Scripts/UI/Shop/UseCase/ShopFormUseCase.cs`
- `Assets/GameMain/Scripts/UI/Templates/GameScene/Controller/ShopFormController.cs` - `Assets/GameMain/Scripts/UI/Shop/Controller/ShopFormController.cs`
- `Assets/GameMain/Scripts/UI/Templates/GameScene/View/ShopForm.cs` - `Assets/GameMain/Scripts/UI/Shop/View/ShopForm.cs`
### 4. 三组件约束只做到了“组装时”,还没做到“出战时” ## 当前未完成
- `CombineArea` 已经要求枪口/轴承/底座三槽都填满才能发起组装。
- 但战斗入口并没有校验“玩家是否拥有可参战的完整塔”。 ### 1. Run 主流程已经形成临时闭环,但还不是正式节点 UI
- 当前可以在没有任何参战塔时直接调用 `StartCombat()`,不符合 `P0-10` 的“未满足三组件时禁止出战”。
- `ProcedureMain` 进入后会创建 Run并打开 `MainForm + TestMenuForm`
- `TestMenuForm` 已不再同时提供三种节点入口,而是通过 `TestMenuFormContext.CurrentNodeType` 只显示当前节点对应的唯一按钮。
- 点击按钮后由 `ProcedureMain` 根据当前 `RunState.CurrentNode` 决定是否允许进入战斗 / 事件 / 商店。
- 节点完成或战斗失败后,`ProcedureMain` 会推进 `RunState`,再重新打开 Hub UI。
- 因此当前已经能从开始游戏后按固定顺序推进一局的临时版本。
当前缺口:
- UI 仍是测试面板,不是正式节点地图或正式节点信息面板。
- `TestMenuFormContext` 目前只传 `CurrentNodeType`还没有显示节点序号、总数、Boss 标记等关键信息。
- Run 完成后的正式结算 / 收尾表现仍未建立。
关键文件:
- `Assets/GameMain/Scripts/Procedure/ProcedureMain.cs`
- `Assets/GameMain/Scripts/UI/Menu/View/TestMenuForm.cs`
- `Assets/GameMain/Scripts/UI/Menu/Controller/TestMenuFormController.cs`
### 2. 固定 10 节点序列已开始驱动真实流程,但上下文仍不完整
- `FixedRunNodeSequenceBuilder` 已定义固定顺序和 Boss 终点。
- `ProcedureMain` 已开始用当前 `RunNodeState.LinkedLevelId` 驱动战斗入口。
- `EventNodeComponent``ShopNodeComponent` 已能进入并完成当前节点。
- `EventNodeComponent` 的 UI 生命周期也已统一走 `UIRouter`
- 但 `NodeEnter / NodeComplete` 仍是默认空载事件,没有附带当前 Run 节点信息。
- 因此“固定 10 节点序列”已经在驱动流程,但还没有形成可观测、可追踪的正式节点上下文系统。
关键文件:
- `Assets/GameMain/Scripts/Procedure/FixedRunNodeSequenceBuilder.cs`
- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatNodeComponent.cs`
- `Assets/GameMain/Scripts/CustomComponent/EventNodeComponent.cs`
- `Assets/GameMain/Scripts/CustomComponent/ShopNodeComponent.cs`
- `Assets/GameMain/Scripts/Event/Game/NodeEnterEventArgs.cs`
- `Assets/GameMain/Scripts/Event/Game/NodeCompleteEventArgs.cs`
### 3. 商店节点已纳入临时 Run 推进闭环,但回流目标仍是测试 Hub
- 现在可以单独打开商店、随机生成组件、购买并退出。
- 商店结束后已能通过 `ProcedureMain` 推进当前 `RunState`
- 但退出后仍是回到 `MainForm + TestMenuForm`,而不是真实节点地图或正式节点选择界面。
关键文件:
- `Assets/GameMain/Scripts/CustomComponent/ShopNodeComponent.cs`
- `Assets/GameMain/Scripts/UI/Shop/UseCase/ShopFormUseCase.cs`
- `Assets/GameMain/Scripts/Procedure/ProcedureMain.cs`
### 4. 出战入口已有最小校验,但离最终验收还差一层
- `CombineArea` 已限制三槽必须齐备才能组塔。
- `ProcedureMain` 已经补上“没有参战塔时禁止进入战斗节点”的最小校验。
- 但这个校验目前仍是“有参战塔即可开战”,还不是“完整三组件合法塔”意义上的最终验收版本。
- 这意味着当前还不满足 `P0-10` 里“未满足三组件时禁止出战”的验收要求。
关键文件: 关键文件:
- `Assets/GameMain/Scripts/UI/Game/View/CombineArea.cs` - `Assets/GameMain/Scripts/UI/Game/View/CombineArea.cs`
- `Assets/GameMain/Scripts/Procedure/ProcedureMain.cs`
- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatNodeComponent.cs` - `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatNodeComponent.cs`
- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatScheduler.cs`
### 5. 品质/槽位/Tag 规则只做了最浅一层 ### 5. 品质 / 槽位 / Tag 规则仍只做了浅层版本
- 塔品质目前只按三组件平均品质四舍五入得到。
- `TowerItemData` 里没有“配件槽位数量”之类的落地字段,槽位规则没有真正实现。 - 塔品质仍主要按三组件品质聚合得到。
- Tag 当前不是按品质概率、数量、等级生成,而是: - `TowerItemData` 中没有真正落地“配件槽位数量”之类的核心字段。
- 掉落时直接复制 `PossibleTag` - Tag 仍主要来自组件自身配置或简单并集,未看到完整概率、数量、等级规则落地。
- 组塔时直接把三组件 Tag 做并集 - `DRTag` 已存在,但尚未形成明确的掉落 / 组装计算主链路。
- `DRTag` 虽然存在,但没有看到被用于实际掉落/组装规则计算。 - `RarityType` 仍保留 `Red`,与部分 M1 文档描述未完全对齐。
- `RarityType` 仍包含 `Red`,而 `docs/MVP-Scope.md.md` 里写的是 M1 不做红色,这里也还没统一。
关键文件: 关键文件:
- `Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerAssemblyService.cs` - `Assets/GameMain/Scripts/CustomComponent/PlayerInventory/PlayerInventoryTowerAssemblyService.cs`
@ -126,12 +165,13 @@
- `Assets/GameMain/Scripts/Definition/DataStruct/TowerItemData.cs` - `Assets/GameMain/Scripts/Definition/DataStruct/TowerItemData.cs`
- `Assets/GameMain/Scripts/Definition/Enum/RarityType.cs` - `Assets/GameMain/Scripts/Definition/Enum/RarityType.cs`
### 6. 耐久只停留在展示和扣数值,没有真正生效 ### 6. 耐久仍停留在“展示 + 部分扣减”,没有形成真实生效闭环
- 当前组件耐久会显示在仓库描述和 UI 颜色上。
- 低血通关后会调用 `ReduceAllTowerEndurance(...)` 扣耐久。 - 当前组件耐久会显示在描述与 UI 上。
- 但塔的真实战斗属性是组装时固化到 `TowerStatsData` 的,不会随着耐久变化动态衰减。 - 低血通关后已存在扣耐久逻辑。
- 组件耐久归 0 后没有销毁、移除库存、拆塔或失效处理。 - 但塔战斗属性是在组装时固化到 `TowerStatsData`,没有根据耐久实时衰减。
- 所以 `P0-12` 的“耐久影响属性,归零后物品移除”目前未完成。 - 组件耐久归 0 后也没有稳定的销毁 / 拆塔 / 失效闭环。
- 因此 `P0-12` 的完整验收还没有达成。
关键文件: 关键文件:
- `Assets/GameMain/Scripts/Utility/ItemDescUtility.cs` - `Assets/GameMain/Scripts/Utility/ItemDescUtility.cs`
@ -139,71 +179,76 @@
- `Assets/GameMain/Scripts/Definition/DataStruct/TowerItemData.cs` - `Assets/GameMain/Scripts/Definition/DataStruct/TowerItemData.cs`
- `Assets/GameMain/Scripts/Definition/DataStruct/TowerCompItemData.cs` - `Assets/GameMain/Scripts/Definition/DataStruct/TowerCompItemData.cs`
### 7. M1 文档与当前实现还有几处范围不一致 ## 当前与 `docs/TODO.md` 的对照判断
- `docs/MVP-Scope.md.md` 写的是固定 10 节点与固定顺序,但当前代码没有对应系统。
- 文档写的是商店节点可购买/出售组件,但当前商店未实现。
- 文档写的是 M1 不做耐久系统,但 `docs/TODO.md` 又把耐久列在 M1 的 `P0-12`;当前代码只做了半套,需要先统一目标再继续推进。
- 文档写的是 M1 不做红色品质,但数据与枚举仍保留 `Red`
关键文件: 结合静态代码检查,当前更接近下面这个状态:
- `docs/TODO.md`
- `docs/MVP-Scope.md.md` - `P0-04`:基础模型已完成,并已接入 `ProcedureMain` 的临时 Run 闭环。
- `docs/GameDesign.md` - `P0-05`:固定 10 节点序列已由 builder + `ProcedureMain` 开始驱动实际流程,但缺完整事件上下文与正式节点 UI。
- `P0-06`:节点进入、完成、失败后回 Hub 的临时闭环已存在,但“正式地图/节点界面 + 正式结算”仍未完成。
- `P0-10`:未完成。
- `P0-11`:未完成。
- `P0-12`:未完成。
换句话说,仓库已经不再是“还没有 Run 模型 / 10 节点 / 商店最小实现”的状态;真正的缺口是“这些能力已经接成临时可跑版本,但还没收口成正式 M1 主流程表现层与上下文系统”。
## 推荐的后续执行顺序 ## 推荐的后续执行顺序
1. 先补单局 Run 模型 1. 先把临时 Hub 升级成正式节点面板
- 明确 `当前节点索引 / 节点列表 / 当前主题 / 大关完成状态` - 保留 `ProcedureMain` 持有 Run 的做法
- 把 `ProcedureMenu + TestMenuForm` 临时入口替换成真实节点推进入口 - 不再把 `TestMenuForm` 当测试菜单,而是改成正式节点信息面板或节点地图
- 至少补上当前节点序号、总节点数、节点名称、Boss 标记
2. 再补 10 节点固定大关 2. 再把节点事件改成带上下文的真实推进
- 先做最小版本:固定顺序 10 节点 - `NodeEnterEventArgs``NodeCompleteEventArgs` 传递 `runId / nodeId / nodeType / sequenceIndex`
- 最后一个节点固定 Boss 战斗 - 节点完成后由流程层调用 `RunStateAdvanceService`
- 节点完成后推进到下一节点 - 节点失败时明确是否停局、重试或返回菜单
3. 立刻补商店节点最小实现 3. 然后继续收口战斗关卡选择
- 先只做 3 个随机组件、购买、返回 - 普通战斗和 Boss 战斗继续统一由当前 `RunNodeState.LinkedLevelId` 驱动
- 不提前做复杂定价与出售扩展 - 去掉遗留的随机选关兜底路径,避免偏离 Run 顺序
4. 收口组装到出战闭环 4. 再补出战合法性校验
- 没有完整塔时禁止开始战斗 - 没有完整参战塔时禁止进入战斗节点
- 只有参战塔列表合法时才允许进入战斗节点 - 在 UI 和流程层都给出明确反馈
5. 最后补品质/Tag/耐久规则 5. 最后再处理品质 / Tag / 耐久与文档对齐
- 先把 M1 真实要做的规则重新对齐 - 先确认 M1 是否真的保留红色品质和完整耐久
- 再决定是否保留红色品质、耐久和槽位到本阶段 - 再决定是补全实现,还是先缩范围并同步文档
## 当前做变更时要记住的约束 ## 当前做变更时要记住的约束
- 不要继续把 `TestMenuForm` 当作正式节点流程 - 不要再把 `TestMenuForm` 维持成“测试菜单”语义
- 优先补“流程闭环”,不要先做 M2 的深度系统 - 优先补“临时闭环 -> 正式节点 UI / 正式上下文”的收口,不要继续只加单点功能
- 商店、节点推进、出战校验属于当前阻塞项,优先级高于数值打磨 - 商店已经接入 Run下一步重点不是继续扩商店而是把 Hub/UI 做正式
- 如果 M1 最终决定不做完整耐久/红色品质,要先同步更新文档,再改代码目标。 - 若 M1 最终不做完整耐久 / 红色品质,要先同步文档再改代码目标。
- 若继续保留 `PlayerInventory` 作为局内外共用库存入口,需要避免把单局 Run 状态也硬塞进去 - `PlayerInventory` 可以继续作为库存入口,但不要把整局 Run 状态直接混进库存对象里
## 当前关键入口文件速查 ## 当前关键入口文件速查
- 流程入口: - 流程入口:
- `Assets/GameMain/Scripts/Procedure/ProcedureMenu.cs` - `Assets/GameMain/Scripts/Procedure/ProcedureMain.cs`
- 临时节点菜单: - Run 模型:
- `Assets/GameMain/Scripts/Procedure/RunModel.cs`
- `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` - `Assets/GameMain/Scripts/UI/Menu/Controller/TestMenuFormController.cs`
- 战斗节点 facade - 战斗节点 facade
- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatNodeComponent.cs` - `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatNodeComponent.cs`
- 战斗状态机:
- `Assets/GameMain/Scripts/CustomComponent/CombatNode/CombatScheduler/CombatScheduler.cs`
- 事件节点: - 事件节点:
- `Assets/GameMain/Scripts/CustomComponent/EventNodeComponent.cs` - `Assets/GameMain/Scripts/CustomComponent/EventNodeComponent.cs`
- 商店节点: - 商店节点:
- `Assets/GameMain/Scripts/CustomComponent/ShopNodeComponent.cs` - `Assets/GameMain/Scripts/CustomComponent/ShopNodeComponent.cs`
- 商店 UI
- `Assets/GameMain/Scripts/UI/Shop/`
- 背包与组装: - 背包与组装:
- `Assets/GameMain/Scripts/CustomComponent/PlayerInventory/` - `Assets/GameMain/Scripts/CustomComponent/PlayerInventory/`
- 仓库 UI
- `Assets/GameMain/Scripts/UI/Game/` - `Assets/GameMain/Scripts/UI/Game/`
- 战斗 UI
- `Assets/GameMain/Scripts/UI/Combat/`
## 备注 ## 备注
- 这份清单按“当前仓库真实实现状态”整理,不沿用旧版 `CodeX-TODO.md` 的 CombatNode 收口主题 - 这份清单基于 2026-03-08 的静态代码检查更新
- 当前判断主要基于代码静态检查,没有跑 Unity Editor / PlayMode - 本次已修正上一版中“Run 模型不存在”“10 节点未实现”“商店节点基本未实现”等过期判断
- 如果下一步要继续推进,最值得先做的是:`RunState + 10 节点流程 + ShopNode 最小可用版`。 - 当前最值得优先推进的是:`ProcedureMain 继续收口 Run 流程 -> 节点事件带上下文 -> 战斗按节点关卡进入 -> 出战校验`。

View File

@ -16,9 +16,9 @@
| [x] | P0-01 | 冻结 MVP 范围(只保留:战斗节点/事件节点/商店节点/节点后组装) | `docs/MVP-Scope.md` | 明确“做/不做”清单,团队评审通过 | | [x] | P0-01 | 冻结 MVP 范围(只保留:战斗节点/事件节点/商店节点/节点后组装) | `docs/MVP-Scope.md` | 明确“做/不做”清单,团队评审通过 |
| [x] | P0-02 | 补齐数据表:组件、配件、敌人、波次、节点、事件、商店商品 | `Assets/GameMain/DataTables/*.txt` | 游戏启动可无报错加载全部新增表 | | [x] | P0-02 | 补齐数据表:组件、配件、敌人、波次、节点、事件、商店商品 | `Assets/GameMain/DataTables/*.txt` | 游戏启动可无报错加载全部新增表 |
| [x] | P0-03 | 新增/完善 DataRow 解析类 | `Assets/GameMain/Scripts/DataTable/*.cs` | 每个新增表都有对应 DR 类并成功解析 | | [x] | P0-03 | 新增/完善 DataRow 解析类 | `Assets/GameMain/Scripts/DataTable/*.cs` | 每个新增表都有对应 DR 类并成功解析 |
| [x] | P0-04 | 建立单局 Run 状态模型(金币、生命、库存、当前节点) | `Assets/GameMain/Scripts/Procedure/` | 进入/退出节点时状态可持续传递 | | [~] | P0-04 | 建立单局 Run 状态模型(金币、生命、库存、当前节点) | `Assets/GameMain/Scripts/Procedure/` | 已有 `RunState` / 推进模型 / 测试,并已接入 `ProcedureMain` 的临时 Run 闭环,但还不是正式节点 UI |
| [ ] | P0-05 | 实现 10 节点地图生成(最后节点固定 Boss | `Assets/GameMain/Scripts/Scene/` | 每局都生成 10 节点且第 10 节点为 Boss | | [~] | P0-05 | 实现 10 节点地图生成(最后节点固定 Boss | `Assets/GameMain/Scripts/Procedure/`<br>`Assets/GameMain/Scripts/Scene/` | 已有固定 10 节点序列 builder 与测试,且已开始驱动真实流程,但节点事件上下文与正式节点面板仍未完成 |
| [x] | P0-06 | 实现节点选择与跳转流程(战斗/事件/商店) | `Assets/GameMain/Scripts/Procedure/` | 节点完成后可返回地图并进入下个节点 | | [~] | P0-06 | 实现节点选择与跳转流程(战斗/事件/商店) | `Assets/GameMain/Scripts/Procedure/` | `ProcedureMain + TestMenuForm` 的临时闭环已可推进战斗/事件/商店,但仍缺正式节点地图/节点面板与正式结算收尾 |
| [x] | P0-07 | 战斗节点基础玩法:放置塔、出怪、基地扣血、胜负判定 | `Assets/GameMain/Scripts/Entity/`<br>`Assets/GameMain/Scripts/Scene/` | 可完整打一场并得到胜利/失败结果 | | [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-08 | 胜利波次与结算规则100/80/50/<50 | `Assets/GameMain/Scripts/Procedure/` | 结算奖励与惩罚严格匹配设计文档 |
| [x] | P0-09 | 敌人掉落与关卡奖励(组件/配件/金币) | `Assets/GameMain/Scripts/Entity/` | 战斗结束能发放掉落并写入库存 | | [x] | P0-09 | 敌人掉落与关卡奖励(组件/配件/金币) | `Assets/GameMain/Scripts/Entity/` | 战斗结束能发放掉落并写入库存 |
@ -55,9 +55,9 @@
## 本周建议开工顺序 ## 本周建议开工顺序
1. `P0-01` ~ `P0-04`(先把范围与数据基础打稳) 1. 先把 `P0-04` ~ `P0-06` 从“临时闭环”收口成正式节点面板 / 节点地图,并补齐节点事件上下文
2. `P0-05` ~ `P0-09`(打通节点到战斗再到结算 2. 完成 `P0-10`(把“至少有参战塔”提升为“满足完整合法参战条件才能出战”
3. `P0-10` ~ `P0-12`(完成组装与耐久闭环 3. 再处理 `P0-11` ~ `P0-12`(品质 / Tag / 耐久是否纳入 M1 需先统一范围
## 设计优化 Backlog新增 ## 设计优化 Backlog新增

Binary file not shown.