RunNode 接入游戏主流程
- NodeMapForm:节点地图
- NodeItem:节点入口
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da34e789554bd744e913db9fa3615322
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb4720747caac9641b0bf06abbdad70f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e24f8a016c2dd9b4b9e7aa34a24185a0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 933dea9978c15484aab9df1bd8f32276
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e35c4c20ae9d48a4c8e9878e79b7d346
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d370c24f0bca1cd49b1163c3765e0f4c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16f09225744e9ed45ba3ed24c27f9602
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8b608c268739c144990195981f1c4465
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,6 +1,9 @@
|
||||
using GeometryTD.Procedure;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class TestMenuFormContext : UIContext
|
||||
{
|
||||
public RunNodeType CurrentNodeType { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3ec06b97e6bc9d743a6340377ab7cd8b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,6 +1,6 @@
|
||||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.Definition;
|
||||
using GameFramework.Event;
|
||||
using GeometryTD.Procedure;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
@@ -16,12 +16,10 @@ namespace GeometryTD.UI
|
||||
|
||||
protected override void SubscribeCustomEvents()
|
||||
{
|
||||
GameEntry.Event.Subscribe(TestMenuNodeClickEventArgs.EventId, OnNodeClick);
|
||||
}
|
||||
|
||||
protected override void UnsubscribeCustomEvents()
|
||||
{
|
||||
GameEntry.Event.Unsubscribe(TestMenuNodeClickEventArgs.EventId, OnNodeClick);
|
||||
}
|
||||
|
||||
public override int? OpenUI(object userData = null)
|
||||
@@ -50,36 +48,10 @@ namespace GeometryTD.UI
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5dc8f63e892ff6745aed855ae42cfd88
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1fc5bfbd1fcf533448f2669b0eda64bf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fdf317aa70fe94f44a332b6ee6ef5bbc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,10 +1,16 @@
|
||||
using GeometryTD.CustomEvent;
|
||||
using GeometryTD.Procedure;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.UI
|
||||
{
|
||||
public class TestMenuForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private GameObject combatButtonObject;
|
||||
[SerializeField] private GameObject eventButtonObject;
|
||||
[SerializeField] private GameObject shopButtonObject;
|
||||
|
||||
private TestMenuFormContext _context;
|
||||
|
||||
public void RefreshUI(TestMenuFormContext context)
|
||||
@@ -12,8 +18,17 @@ namespace GeometryTD.UI
|
||||
_context = context;
|
||||
if (_context == null)
|
||||
{
|
||||
SetButtonVisible(combatButtonObject, false);
|
||||
SetButtonVisible(eventButtonObject, false);
|
||||
SetButtonVisible(shopButtonObject, false);
|
||||
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()
|
||||
@@ -47,8 +62,19 @@ namespace GeometryTD.UI
|
||||
protected override void OnClose(bool isShutdown, object userData)
|
||||
{
|
||||
_context = null;
|
||||
SetButtonVisible(combatButtonObject, false);
|
||||
SetButtonVisible(eventButtonObject, false);
|
||||
SetButtonVisible(shopButtonObject, false);
|
||||
|
||||
base.OnClose(isShutdown, userData);
|
||||
}
|
||||
|
||||
private static void SetButtonVisible(GameObject buttonObject, bool visible)
|
||||
{
|
||||
if (buttonObject != null)
|
||||
{
|
||||
buttonObject.SetActive(visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user