迁移剩下的 UI 到 Serialization 方式
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Luban;
|
||||
|
||||
|
||||
namespace SepCore.Definition
|
||||
{
|
||||
public sealed partial class FormatText : Luban.BeanBase
|
||||
{
|
||||
public FormatText(ByteBuf _buf)
|
||||
{
|
||||
Name = _buf.ReadString();
|
||||
Format = _buf.ReadString();
|
||||
}
|
||||
|
||||
public static FormatText DeserializeFormatText(ByteBuf _buf)
|
||||
{
|
||||
return new FormatText(_buf);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文本名
|
||||
/// </summary>
|
||||
public readonly string Name;
|
||||
/// <summary>
|
||||
/// 格式化字符串
|
||||
/// </summary>
|
||||
public readonly string Format;
|
||||
|
||||
public const int __ID__ = -1977697820;
|
||||
public override int GetTypeId() => __ID__;
|
||||
|
||||
public void ResolveRef(Tables tables)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{ "
|
||||
+ "name:" + Name + ","
|
||||
+ "format:" + Format + ","
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f21ab051c635de04998b80804d9bafe5
|
||||
guid: 721766cc68542b640a2119ab0c73a833
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -21,6 +21,7 @@ public partial class Tables
|
||||
/// 实体配置
|
||||
/// </summary>
|
||||
public TbEntityConfig TbEntityConfig {get; }
|
||||
public TbFormatText TbFormatText {get; }
|
||||
/// <summary>
|
||||
/// 全局零散配置(单例)
|
||||
/// </summary>
|
||||
@@ -65,6 +66,7 @@ public partial class Tables
|
||||
{
|
||||
TbEnemyConfig = new TbEnemyConfig(loader("tbenemyconfig"));
|
||||
TbEntityConfig = new TbEntityConfig(loader("tbentityconfig"));
|
||||
TbFormatText = new TbFormatText(loader("tbformattext"));
|
||||
TbGlobalConfig = new TbGlobalConfig(loader("tbglobalconfig"));
|
||||
TbGoodsConfig = new TbGoodsConfig(loader("tbgoodsconfig"));
|
||||
TbLevelConfig = new TbLevelConfig(loader("tblevelconfig"));
|
||||
@@ -87,6 +89,7 @@ public partial class Tables
|
||||
{
|
||||
TbEnemyConfig.ResolveRef(this);
|
||||
TbEntityConfig.ResolveRef(this);
|
||||
TbFormatText.ResolveRef(this);
|
||||
TbGlobalConfig.ResolveRef(this);
|
||||
TbGoodsConfig.ResolveRef(this);
|
||||
TbLevelConfig.ResolveRef(this);
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using Luban;
|
||||
|
||||
|
||||
namespace SepCore.Definition
|
||||
{
|
||||
public partial class TbFormatText
|
||||
{
|
||||
private readonly System.Collections.Generic.Dictionary<string, FormatText> _dataMap;
|
||||
private readonly System.Collections.Generic.List<FormatText> _dataList;
|
||||
|
||||
public TbFormatText(ByteBuf _buf)
|
||||
{
|
||||
_dataMap = new System.Collections.Generic.Dictionary<string, FormatText>();
|
||||
_dataList = new System.Collections.Generic.List<FormatText>();
|
||||
|
||||
for(int n = _buf.ReadSize() ; n > 0 ; --n)
|
||||
{
|
||||
FormatText _v;
|
||||
_v = FormatText.DeserializeFormatText(_buf);
|
||||
_dataList.Add(_v);
|
||||
_dataMap.Add(_v.Name, _v);
|
||||
}
|
||||
}
|
||||
|
||||
public System.Collections.Generic.Dictionary<string, FormatText> DataMap => _dataMap;
|
||||
public System.Collections.Generic.List<FormatText> DataList => _dataList;
|
||||
|
||||
public FormatText GetOrDefault(string key) => _dataMap.TryGetValue(key, out var v) ? v : null;
|
||||
public FormatText Get(string key) => _dataMap[key];
|
||||
public FormatText this[string key] => _dataMap[key];
|
||||
|
||||
public void ResolveRef(Tables tables)
|
||||
{
|
||||
foreach(var _v in _dataList)
|
||||
{
|
||||
_v.ResolveRef(tables);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8574165ef5ddc674fb6c69eaab38a63e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -72,7 +72,6 @@ namespace SepCore.Editor
|
||||
private sealed class Binding
|
||||
{
|
||||
public Component component;
|
||||
public UISerializationRoot nestedRoot;
|
||||
public string variableName;
|
||||
public string csharpTypeName;
|
||||
}
|
||||
@@ -129,7 +128,7 @@ namespace SepCore.Editor
|
||||
|
||||
List<UISerializationRoot> generationRoots = CollectGenerationRoots(root);
|
||||
List<GenerationUnit> units = BuildGenerationUnits(generationRoots);
|
||||
GenerationUnit primaryUnit = units[units.Count - 1];
|
||||
GenerationUnit primaryUnit = units[0];
|
||||
|
||||
List<string> changedExistingFiles = units
|
||||
.Where(unit => unit.SourceChanged)
|
||||
@@ -382,35 +381,8 @@ namespace SepCore.Editor
|
||||
private static List<UISerializationRoot> CollectGenerationRoots(UISerializationRoot selectedRoot)
|
||||
{
|
||||
bool persistentContext = EditorUtility.IsPersistent(selectedRoot);
|
||||
var result = new List<UISerializationRoot>();
|
||||
var visited = new HashSet<UISerializationRoot>();
|
||||
CollectGenerationRootsRecursive(selectedRoot, persistentContext, visited, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void CollectGenerationRootsRecursive(
|
||||
UISerializationRoot current,
|
||||
bool persistentContext,
|
||||
HashSet<UISerializationRoot> visited,
|
||||
List<UISerializationRoot> result)
|
||||
{
|
||||
current = GetCanonicalRoot(current, persistentContext);
|
||||
if (current == null || !visited.Add(current))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
current.RefreshItems();
|
||||
for (int i = 0; i < current.NestedFormReferences.Count; i++)
|
||||
{
|
||||
UISerializationRoot nestedRoot = current.NestedFormReferences[i].Root;
|
||||
if (nestedRoot != null)
|
||||
{
|
||||
CollectGenerationRootsRecursive(nestedRoot, persistentContext, visited, result);
|
||||
}
|
||||
}
|
||||
|
||||
result.Add(current);
|
||||
UISerializationRoot generationRoot = GetCanonicalRoot(selectedRoot, persistentContext);
|
||||
return new List<UISerializationRoot> { generationRoot };
|
||||
}
|
||||
|
||||
private static UISerializationRoot GetCanonicalRoot(UISerializationRoot root, bool persistentContext)
|
||||
@@ -533,18 +505,51 @@ namespace SepCore.Editor
|
||||
throw new InvalidOperationException("A nested UI Form reference is missing below " + GetHierarchyPath(root.transform) + ".");
|
||||
}
|
||||
|
||||
UGuiForm nestedForm = FindNestedForm(nestedRoot, out string nestedFormError);
|
||||
if (nestedForm == null)
|
||||
{
|
||||
throw new InvalidOperationException(nestedFormError);
|
||||
}
|
||||
|
||||
string variableName = NormalizeAndValidateVariableName(reference.VariableName, nestedRoot.transform, names);
|
||||
bindings.Add(new Binding
|
||||
{
|
||||
nestedRoot = nestedRoot,
|
||||
component = nestedForm,
|
||||
variableName = variableName,
|
||||
csharpTypeName = "global::" + GeneratedNamespace + "." + GetFormClassName(nestedRoot)
|
||||
csharpTypeName = GetCSharpTypeName(nestedForm.GetType())
|
||||
});
|
||||
}
|
||||
|
||||
return bindings;
|
||||
}
|
||||
|
||||
public static UGuiForm FindNestedForm(UISerializationRoot nestedRoot, out string error)
|
||||
{
|
||||
error = null;
|
||||
if (nestedRoot == null)
|
||||
{
|
||||
error = "The nested UI root is missing.";
|
||||
return null;
|
||||
}
|
||||
|
||||
UGuiForm[] forms = nestedRoot.GetComponents<UGuiForm>();
|
||||
if (forms.Length == 0)
|
||||
{
|
||||
error = "Nested UI root '" + GetHierarchyPath(nestedRoot.transform) +
|
||||
"' does not have a UGuiForm component. Generate its View & Form scripts first.";
|
||||
return null;
|
||||
}
|
||||
|
||||
if (forms.Length > 1)
|
||||
{
|
||||
error = "Nested UI root '" + GetHierarchyPath(nestedRoot.transform) +
|
||||
"' has multiple UGuiForm components.";
|
||||
return null;
|
||||
}
|
||||
|
||||
return forms[0];
|
||||
}
|
||||
|
||||
private static string NormalizeAndValidateVariableName(string value, Transform owner, HashSet<string> names)
|
||||
{
|
||||
string variableName = value == null ? string.Empty : value.Trim();
|
||||
@@ -755,26 +760,7 @@ namespace SepCore.Editor
|
||||
throw new InvalidOperationException("Generated field was not found: " + binding.variableName + ".");
|
||||
}
|
||||
|
||||
UnityEngine.Object target = binding.component;
|
||||
if (binding.nestedRoot != null)
|
||||
{
|
||||
string nestedFormFullName = GeneratedNamespace + "." + GetFormClassName(binding.nestedRoot);
|
||||
Type nestedFormType = FindGeneratedType(nestedFormFullName);
|
||||
if (nestedFormType == null)
|
||||
{
|
||||
throw new InvalidOperationException("Nested UI form type was not found: " + nestedFormFullName + ".");
|
||||
}
|
||||
|
||||
target = binding.nestedRoot.GetComponent(nestedFormType);
|
||||
if (target == null)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Nested UI root '" + GetHierarchyPath(binding.nestedRoot.transform) +
|
||||
"' does not have its generated Form component '" + nestedFormFullName + "'.");
|
||||
}
|
||||
}
|
||||
|
||||
property.objectReferenceValue = target;
|
||||
property.objectReferenceValue = binding.component;
|
||||
}
|
||||
|
||||
serializedView.ApplyModifiedProperties();
|
||||
|
||||
@@ -107,7 +107,15 @@ namespace SepCore.Editor
|
||||
|
||||
if (nestedRoot != null)
|
||||
{
|
||||
EditorGUILayout.LabelField("Form Class", UIAssetsTools.GetFormClassName(nestedRoot));
|
||||
UGuiForm nestedForm = UIAssetsTools.FindNestedForm(nestedRoot, out string nestedFormError);
|
||||
if (nestedForm != null)
|
||||
{
|
||||
EditorGUILayout.LabelField("Form Class", nestedForm.GetType().FullName);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox(nestedFormError, MessageType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (generate.boolValue)
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
using SepCore.Definition;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// 使用 Luban 格式化文本表(TbFormatText)驱动 TextMeshProUGUI 的组件。
|
||||
/// 在 Inspector 上填写 Key,调用 Set 传入格式化参数即可更新文本。
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(TextMeshProUGUI))]
|
||||
public class FormatTextUI : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private string key;
|
||||
|
||||
private TextMeshProUGUI _text;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_text = GetComponent<TextMeshProUGUI>();
|
||||
}
|
||||
|
||||
public void Set(params object[] args)
|
||||
{
|
||||
FormatText format = GameEntry.Luban.Tables.TbFormatText.GetOrDefault(key);
|
||||
if (format == null)
|
||||
{
|
||||
Log.Warning("Can not find format text '{0}'.", key);
|
||||
return;
|
||||
}
|
||||
|
||||
_text.SetText(string.Format(format.Format, args));
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_text.SetText(string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2efdcd06cdaa830448f76b22ea7c98fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16815ca7d82e7ea4c91dd017189eeacb
|
||||
guid: 0a0edeeb11ca93846b60f6fbb75452a9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
+24
-8
@@ -11,18 +11,19 @@ namespace SepCore.UI
|
||||
[SerializeField] private IconArea _iconArea;
|
||||
|
||||
[SerializeField] private RectTransform _itemRect;
|
||||
|
||||
[SerializeField] private CommonButton _button;
|
||||
|
||||
private DisplayItemContext _context;
|
||||
|
||||
private int _index = -1;
|
||||
|
||||
public void SetIndex(int index)
|
||||
{
|
||||
_index = index;
|
||||
}
|
||||
private bool _listenersBound;
|
||||
|
||||
public async UniTaskVoid OnInit(DisplayItemContext context, int index)
|
||||
{
|
||||
EnsureListeners();
|
||||
|
||||
_context = context;
|
||||
_index = index;
|
||||
|
||||
@@ -38,7 +39,22 @@ namespace SepCore.UI
|
||||
_iconArea.OnReset();
|
||||
}
|
||||
|
||||
public void OnItemInfoShow()
|
||||
private void EnsureListeners()
|
||||
{
|
||||
if (_listenersBound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_listenersBound = true;
|
||||
|
||||
CommonButton button = GetComponent<CommonButton>();
|
||||
button.onClick.AddListener(OnItemInfoLock);
|
||||
button.RegisterPointerEnterAction(OnItemInfoShow);
|
||||
button.RegisterPointerExitAction(OnItemInfoHide);
|
||||
}
|
||||
|
||||
private void OnItemInfoShow()
|
||||
{
|
||||
if (_index < 0) return;
|
||||
|
||||
@@ -51,14 +67,14 @@ namespace SepCore.UI
|
||||
GameEntry.Event.Fire(this, DisplayItemHoverEventArgs.Create(_index, _context.IsWeapon, targetPos));
|
||||
}
|
||||
|
||||
public void OnItemInfoLock()
|
||||
private void OnItemInfoLock()
|
||||
{
|
||||
GameEntry.Event.Fire(this, DisplayItemLockEventArgs.Create());
|
||||
}
|
||||
|
||||
public void OnItemInfoHide()
|
||||
private void OnItemInfoHide()
|
||||
{
|
||||
GameEntry.Event.Fire(this, DisplayItemHideEventArgs.Create());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace SepCore.UI
|
||||
{
|
||||
public class DisplayListContext : UIContext
|
||||
{
|
||||
public int CurrentCount;
|
||||
public int MaxCount = -1;
|
||||
public DisplayItemContext[] ItemContexts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
public partial class DisplayListForm
|
||||
{
|
||||
private readonly List<DisplayItem> _displayItems = new List<DisplayItem>();
|
||||
|
||||
public void OnInit(DisplayListContext context)
|
||||
{
|
||||
View.titleFormatText.Set(context.CurrentCount, context.MaxCount);
|
||||
|
||||
int targetCount = Mathf.Min(context.CurrentCount, context.ItemContexts.Length);
|
||||
EnsureItemCount(targetCount);
|
||||
|
||||
for (int i = 0; i < _displayItems.Count; i++)
|
||||
{
|
||||
DisplayItem item = _displayItems[i];
|
||||
if (i < targetCount)
|
||||
{
|
||||
item.OnInit(context.ItemContexts[i], i).Forget();
|
||||
item.gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.OnReset();
|
||||
item.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnReset()
|
||||
{
|
||||
for (int i = 0; i < _displayItems.Count; i++)
|
||||
{
|
||||
_displayItems[i].OnReset();
|
||||
_displayItems[i].gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureItemCount(int count)
|
||||
{
|
||||
while (_displayItems.Count < count)
|
||||
{
|
||||
DisplayItem item = Instantiate(View.displayItemTemplate, View.listRoot.transform);
|
||||
_displayItems.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class DisplayListForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private DisplayListView _view = null;
|
||||
|
||||
public DisplayListView View => _view;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 220e0137e2c60eb4084e50234225dd50
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class DisplayListView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI titleFormatText;
|
||||
[SerializeField] public global::UnityEngine.UI.GridLayoutGroup listRoot;
|
||||
[SerializeField] public global::SepCore.UI.DisplayItem displayItemTemplate;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d9eb9bf8c92339346b767aa476f14f94
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d21ab27094da2548a00119313150780
|
||||
guid: ec716511ca2cd8043bff922575851a1b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
+13
-40
@@ -2,47 +2,29 @@ using System.Collections;
|
||||
using SepCore.Event;
|
||||
using GameFramework.Event;
|
||||
using SepCore.EnemyManager;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using Unity.Profiling;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
public class HudForm : UGuiForm
|
||||
public partial class HudForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private float _sliderFadeDuration = 0.5f;
|
||||
|
||||
[SerializeField] private Slider _hpSlider;
|
||||
|
||||
[SerializeField] private TMP_Text _hpText;
|
||||
|
||||
private float _currentHpPercent = 0;
|
||||
private Coroutine _hpSliderFadeCoroutine;
|
||||
|
||||
[SerializeField] private Slider _expSlider;
|
||||
|
||||
private float _currentExpPercent = 0;
|
||||
private Coroutine _expSliderFadeCoroutine;
|
||||
|
||||
[SerializeField] private TMP_Text _expText;
|
||||
|
||||
private int _playerCurrentLevel = 1;
|
||||
|
||||
[SerializeField] private TMP_Text _coinText;
|
||||
private int _currentCoin = 0;
|
||||
|
||||
[SerializeField] private TMP_Text _levelTimeLeftText;
|
||||
private int _currentTimeLeft = 0;
|
||||
|
||||
[SerializeField] private TMP_Text _enemyCountText;
|
||||
private EnemyManagerComponent _enemy;
|
||||
|
||||
[SerializeField] private GameObject _movePromptRoot;
|
||||
[SerializeField] private TMP_Text _movePromptText;
|
||||
|
||||
[SerializeField] private TMP_Text _cpuTimeCostText;
|
||||
|
||||
[SerializeField] private float _performanceStatsRefreshInterval = 0.2f;
|
||||
|
||||
private ProfilerRecorder _cpuTimeRecorder;
|
||||
@@ -57,8 +39,8 @@ namespace SepCore.UI
|
||||
public void RefreshMovePrompt(string prompt)
|
||||
{
|
||||
bool visible = !string.IsNullOrEmpty(prompt);
|
||||
_movePromptRoot.SetActive(visible);
|
||||
_movePromptText.text = prompt;
|
||||
View.inputPromptObject.gameObject.SetActive(visible);
|
||||
View.inputPromptText.text = prompt;
|
||||
}
|
||||
|
||||
#region FSM
|
||||
@@ -145,15 +127,7 @@ namespace SepCore.UI
|
||||
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
base.OnUpdate(elapseSeconds, realElapseSeconds);
|
||||
if (_enemy == null)
|
||||
{
|
||||
_enemy = GameEntry.EnemyManager;
|
||||
}
|
||||
|
||||
if (_enemy != null)
|
||||
{
|
||||
_enemyCountText.text = $"Enemy: {_enemy.CurrentEnemyCount}";
|
||||
}
|
||||
View.enemyCountFormatText.Set(_enemy.CurrentEnemyCount);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -179,14 +153,13 @@ namespace SepCore.UI
|
||||
|
||||
if (!hasCpuFrame)
|
||||
{
|
||||
_cpuTimeCostText.text =
|
||||
"CPU Frame: -- ms\nSimulation: -- ms\nJob Wait: -- ms";
|
||||
View.cpuTimeCostFormatText.Set(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
float cpuFrameMilliseconds = cpuFrameNanoseconds / 1_000_000f;
|
||||
|
||||
_cpuTimeCostText.SetText("CPU Frame: {0:2} ms",cpuFrameMilliseconds);
|
||||
|
||||
View.cpuTimeCostFormatText.Set(cpuFrameMilliseconds);
|
||||
}
|
||||
|
||||
private static bool TryGetLastValue(ProfilerRecorder recorder, out long value)
|
||||
@@ -207,7 +180,7 @@ namespace SepCore.UI
|
||||
{
|
||||
if (!(e is PlayerHealthChangeEventArgs args)) return;
|
||||
|
||||
_hpText.text = $"{args.CurrentHealth}/{args.MaxHealth}";
|
||||
View.hpFormatText.Set(args.CurrentHealth, args.MaxHealth);
|
||||
|
||||
float percent = (float)args.CurrentHealth / args.MaxHealth;
|
||||
if (Mathf.Approximately(_currentHpPercent, percent)) return;
|
||||
@@ -215,7 +188,7 @@ namespace SepCore.UI
|
||||
_currentHpPercent = percent;
|
||||
|
||||
if (_hpSliderFadeCoroutine != null) StopCoroutine(_hpSliderFadeCoroutine);
|
||||
_hpSliderFadeCoroutine = StartCoroutine(_hpSlider.SmoothValue(percent, _sliderFadeDuration));
|
||||
_hpSliderFadeCoroutine = StartCoroutine(View.hpSlider.SmoothValue(percent, _sliderFadeDuration));
|
||||
}
|
||||
|
||||
private void PlayerExpChange(object sender, GameEventArgs e)
|
||||
@@ -227,7 +200,7 @@ namespace SepCore.UI
|
||||
_currentExpPercent = percent;
|
||||
|
||||
if (_expSliderFadeCoroutine != null) StopCoroutine(_expSliderFadeCoroutine);
|
||||
_expSliderFadeCoroutine = StartCoroutine(_expSlider.SmoothValue(percent, _sliderFadeDuration));
|
||||
_expSliderFadeCoroutine = StartCoroutine(View.expSlider.SmoothValue(percent, _sliderFadeDuration));
|
||||
}
|
||||
|
||||
private void PlayerLevelUp(object sender, GameEventArgs e)
|
||||
@@ -235,7 +208,7 @@ namespace SepCore.UI
|
||||
if (!(e is PlayerLevelUpEventArgs)) return;
|
||||
|
||||
_playerCurrentLevel++;
|
||||
_expText.text = $"LV.{_playerCurrentLevel}";
|
||||
View.expFormatText.Set(_playerCurrentLevel);
|
||||
}
|
||||
|
||||
private void PlayerCoinChange(object sender, GameEventArgs e)
|
||||
@@ -243,7 +216,7 @@ namespace SepCore.UI
|
||||
if (!(e is PlayerCoinChangeEventArgs args)) return;
|
||||
if (_currentCoin == args.CoinCount) return;
|
||||
|
||||
_coinText.text = $"<sprite name=\"coin\" index=0> {args.CoinCount}";
|
||||
View.coinFormatText.Set(args.CoinCount);
|
||||
_currentCoin = args.CoinCount;
|
||||
}
|
||||
|
||||
@@ -253,7 +226,7 @@ namespace SepCore.UI
|
||||
if (_currentTimeLeft == args.LevelTimeLeft) return;
|
||||
|
||||
_currentTimeLeft = args.LevelTimeLeft;
|
||||
_levelTimeLeftText.text = _currentTimeLeft.ToString();
|
||||
View.countdownText.text = _currentTimeLeft.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -0,0 +1,13 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class HudForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private HudView _view = null;
|
||||
|
||||
public HudView View => _view;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f50fc6aab9e9b4846b0a80dd670c94b7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class HudView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::UnityEngine.UI.Slider hpSlider;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI hpFormatText;
|
||||
[SerializeField] public global::UnityEngine.UI.Slider expSlider;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI expFormatText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI coinFormatText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI enemyCountFormatText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI cpuTimeCostFormatText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI countdownText;
|
||||
[SerializeField] public global::UnityEngine.RectTransform inputPromptObject;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI inputPromptText;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 128e0c828a462a242a89114f9c8b9d32
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+50
-49
@@ -2,28 +2,13 @@ using System;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using SepCore.AsyncTask;
|
||||
using SepCore.Event;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
public class ItemTooltipForm : UGuiForm
|
||||
public partial class ItemTooltipForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private RectTransform _content;
|
||||
|
||||
[SerializeField] private IconArea _iconArea;
|
||||
|
||||
[SerializeField] private TMP_Text _itemTitle;
|
||||
|
||||
[SerializeField] private TMP_Text _itemTypeText;
|
||||
|
||||
[SerializeField] private TMP_Text _itemDescription;
|
||||
|
||||
[SerializeField] private CommonButton _recycleButton;
|
||||
|
||||
[SerializeField] private TMP_Text _itemPrice;
|
||||
|
||||
[SerializeField] private bool _autoResizeHeight = true;
|
||||
|
||||
[SerializeField] private float _fixedTopHeight = 150f;
|
||||
@@ -38,21 +23,24 @@ namespace SepCore.UI
|
||||
|
||||
private Vector3 _targetPos;
|
||||
|
||||
private bool _listenersBound;
|
||||
|
||||
public async UniTaskVoid RefreshUI(ItemTooltipContext context)
|
||||
{
|
||||
EnsureListeners();
|
||||
|
||||
_context = context;
|
||||
|
||||
_targetPos = ConvertWorldToAnchored(_context.TargetPos);
|
||||
Log.Info($"{_context.TargetPos}->{_targetPos}");
|
||||
|
||||
_content.anchoredPosition3D = _targetPos;
|
||||
View.contentRectTransform.anchoredPosition3D = _targetPos;
|
||||
|
||||
_itemTitle.text = _context.Title;
|
||||
_itemTypeText.text = BuildTypeText(_context.ItemType);
|
||||
_itemDescription.text = _context.Description;
|
||||
_itemPrice.text = $"{_context.Price} <sprite name=\"coin\" index=0>";
|
||||
View.titleText.text = _context.Title;
|
||||
View.typeText.text = BuildTypeText(_context.ItemType);
|
||||
View.infoText.text = _context.Description;
|
||||
View.textFormatText.Set(_context.Price);
|
||||
|
||||
_recycleButton.gameObject.SetActive(_context.ShowRecycleButton);
|
||||
View.recycleButton.gameObject.SetActive(_context.ShowRecycleButton);
|
||||
|
||||
if (!string.IsNullOrEmpty(_context.IconAssetName))
|
||||
{
|
||||
@@ -60,7 +48,7 @@ namespace SepCore.UI
|
||||
var sprite = await SpriteLoader.LoadSpriteByKeyAsync(iconAssetName);
|
||||
if (_context != null && _context.IconAssetName == iconAssetName)
|
||||
{
|
||||
_iconArea.OnInit(sprite, context.Rarity);
|
||||
View.iconArea.OnInit(sprite, context.Rarity);
|
||||
ResizeToFitContent();
|
||||
ApplyClampedTargetPos();
|
||||
}
|
||||
@@ -74,7 +62,7 @@ namespace SepCore.UI
|
||||
{
|
||||
base.OnOpen(userData);
|
||||
|
||||
if (!(userData is ItemTooltipContext context))
|
||||
if (userData is not ItemTooltipContext context)
|
||||
{
|
||||
Log.Error("ItemTooltipForm context is invalid.");
|
||||
return;
|
||||
@@ -89,6 +77,29 @@ namespace SepCore.UI
|
||||
base.OnClose(isShutdown, userData);
|
||||
}
|
||||
|
||||
public void OnRecycleButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, ItemTooltipRecycleEventArgs.Create(_context.Index, _context.Price));
|
||||
}
|
||||
|
||||
public void OnCancelButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, ItemTooltipHideEventArgs.Create());
|
||||
}
|
||||
|
||||
private void EnsureListeners()
|
||||
{
|
||||
if (_listenersBound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_listenersBound = true;
|
||||
|
||||
View.recycleButton.onClick.AddListener(OnRecycleButtonClick);
|
||||
View.cancelButton.onClick.AddListener(OnCancelButtonClick);
|
||||
}
|
||||
|
||||
private void ResizeToFitContent()
|
||||
{
|
||||
if (!_autoResizeHeight)
|
||||
@@ -96,32 +107,32 @@ namespace SepCore.UI
|
||||
return;
|
||||
}
|
||||
|
||||
_itemDescription.ForceMeshUpdate();
|
||||
var descriptionSize = _itemDescription.rectTransform.sizeDelta;
|
||||
descriptionSize.y = _itemDescription.preferredHeight;
|
||||
_itemDescription.rectTransform.sizeDelta = descriptionSize;
|
||||
float descriptionHeight = Mathf.Max(0f, _itemDescription.preferredHeight);
|
||||
View.infoText.ForceMeshUpdate();
|
||||
var descriptionSize = View.infoText.rectTransform.sizeDelta;
|
||||
descriptionSize.y = View.infoText.preferredHeight;
|
||||
View.infoText.rectTransform.sizeDelta = descriptionSize;
|
||||
float descriptionHeight = Mathf.Max(0f, View.infoText.preferredHeight);
|
||||
float targetHeight = _fixedTopHeight + descriptionHeight + _fixedBottomHeight;
|
||||
|
||||
Vector2 size = new Vector2(_fixedWidth, targetHeight);
|
||||
_content.sizeDelta = size;
|
||||
View.contentRectTransform.sizeDelta = size;
|
||||
}
|
||||
|
||||
private void ApplyClampedTargetPos()
|
||||
{
|
||||
RectTransform parent = _content.parent as RectTransform;
|
||||
RectTransform parent = View.contentRectTransform.parent as RectTransform;
|
||||
if (parent == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Vector2 size = _content.sizeDelta;
|
||||
Vector2 size = View.contentRectTransform.sizeDelta;
|
||||
if (size.x <= 0f || size.y <= 0f)
|
||||
{
|
||||
size = _content.rect.size;
|
||||
size = View.contentRectTransform.rect.size;
|
||||
}
|
||||
|
||||
Vector2 pivot = _content.pivot;
|
||||
Vector2 pivot = View.contentRectTransform.pivot;
|
||||
float halfWidth = parent.rect.width * 0.5f;
|
||||
float halfHeight = parent.rect.height * 0.5f;
|
||||
|
||||
@@ -133,18 +144,18 @@ namespace SepCore.UI
|
||||
float clampedX = minX <= maxX ? Mathf.Clamp(_targetPos.x, minX, maxX) : 0f;
|
||||
float clampedY = minY <= maxY ? Mathf.Clamp(_targetPos.y, minY, maxY) : 0f;
|
||||
|
||||
_content.anchoredPosition3D = new Vector3(clampedX, clampedY, _targetPos.z);
|
||||
View.contentRectTransform.anchoredPosition3D = new Vector3(clampedX, clampedY, _targetPos.z);
|
||||
}
|
||||
|
||||
private Vector3 ConvertWorldToAnchored(Vector3 worldPos)
|
||||
{
|
||||
RectTransform parent = _content.parent as RectTransform;
|
||||
RectTransform parent = View.contentRectTransform.parent as RectTransform;
|
||||
if (parent == null)
|
||||
{
|
||||
return worldPos;
|
||||
}
|
||||
|
||||
Canvas canvas = _content.GetComponentInParent<Canvas>();
|
||||
Canvas canvas = View.contentRectTransform.GetComponentInParent<Canvas>();
|
||||
Canvas rootCanvas = canvas != null ? canvas.rootCanvas : null;
|
||||
Camera uiCamera = null;
|
||||
if (rootCanvas != null && rootCanvas.renderMode != RenderMode.ScreenSpaceOverlay)
|
||||
@@ -159,20 +170,10 @@ namespace SepCore.UI
|
||||
return worldPos;
|
||||
}
|
||||
|
||||
float z = _content.anchoredPosition3D.z;
|
||||
float z = View.contentRectTransform.anchoredPosition3D.z;
|
||||
return new Vector3(localPoint.x, localPoint.y, z);
|
||||
}
|
||||
|
||||
public void OnRecycleButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, ItemTooltipRecycleEventArgs.Create(_context.Index, _context.Price));
|
||||
}
|
||||
|
||||
public void OnCancelButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, ItemTooltipHideEventArgs.Create());
|
||||
}
|
||||
|
||||
private string BuildTypeText(ItemType type)
|
||||
{
|
||||
return type switch
|
||||
@@ -0,0 +1,13 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class ItemTooltipForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private ItemTooltipView _view = null;
|
||||
|
||||
public ItemTooltipView View => _view;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7489a7d3442947647bee8612880a3f83
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class ItemTooltipView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::UnityEngine.RectTransform contentRectTransform;
|
||||
[SerializeField] public global::SepCore.UI.IconArea iconArea;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI titleText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI typeText;
|
||||
[SerializeField] public global::TMPro.TextMeshProUGUI infoText;
|
||||
[SerializeField] public global::SepCore.UI.CommonButton recycleButton;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI textFormatText;
|
||||
[SerializeField] public global::SepCore.UI.CommonButton cancelButton;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4d9524b70efb9c840a84baed8b0c12d0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,108 @@
|
||||
using System.Collections.Generic;
|
||||
using SepCore.Event;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
public partial class LevelUpForm : UGuiForm
|
||||
{
|
||||
private readonly List<LevelUpRewardItem> _rewardItems = new List<LevelUpRewardItem>();
|
||||
|
||||
private LevelUpContext _context;
|
||||
|
||||
private bool _listenersBound;
|
||||
|
||||
public void RefreshUI(LevelUpContext context)
|
||||
{
|
||||
EnsureButtonListeners();
|
||||
|
||||
_context = context;
|
||||
|
||||
if (View.levelUpRewardTemplate.gameObject.activeSelf)
|
||||
{
|
||||
View.levelUpRewardTemplate.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
int count = _context.Props?.Count ?? 0;
|
||||
EnsureRewardItemCount(count);
|
||||
|
||||
for (int i = 0; i < _rewardItems.Count; i++)
|
||||
{
|
||||
LevelUpRewardItem item = _rewardItems[i];
|
||||
if (i < count)
|
||||
{
|
||||
item.Init(_context.Props[i]);
|
||||
item.gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
// 刷新 -20 <sprite name="coin" index=0>
|
||||
View.refreshCostFormatText.Set(context.RefreshPrice);
|
||||
}
|
||||
|
||||
#region Lifecycle
|
||||
|
||||
protected override void OnOpen(object userData)
|
||||
{
|
||||
base.OnOpen(userData);
|
||||
|
||||
if (userData is not LevelUpContext context)
|
||||
{
|
||||
Log.Error("LevelUpForm requires LevelUpContext as userData.");
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshUI(context);
|
||||
}
|
||||
|
||||
protected override void OnClose(bool isShutdown, object userData)
|
||||
{
|
||||
_context = null;
|
||||
base.OnClose(isShutdown, userData);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void EnsureButtonListeners()
|
||||
{
|
||||
if (_listenersBound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_listenersBound = true;
|
||||
|
||||
View.refreshButton.onClick.AddListener(OnRefreshButtonClick);
|
||||
}
|
||||
|
||||
private void EnsureRewardItemCount(int count)
|
||||
{
|
||||
while (_rewardItems.Count < count)
|
||||
{
|
||||
int index = _rewardItems.Count;
|
||||
LevelUpRewardItem item = Instantiate(View.levelUpRewardTemplate, View.rewardAreaRoot);
|
||||
CommonButton button = item.GetComponentInChildren<CommonButton>();
|
||||
if (button != null)
|
||||
{
|
||||
button.onClick.AddListener(() => OnSelectButtonClick(index));
|
||||
}
|
||||
|
||||
_rewardItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnSelectButtonClick(int index)
|
||||
{
|
||||
GameEntry.Event.Fire(this, LevelUpPropSelectedEventArgs.Create(index));
|
||||
}
|
||||
|
||||
public void OnRefreshButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, LevelUpRefreshEventArgs.Create(_context.RefreshPrice));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class LevelUpForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private LevelUpView _view = null;
|
||||
|
||||
public LevelUpView View => _view;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3172a8000d5463f45b2f4c5f5a19433d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 32bf4a12bd0ac2847b19bbb76b7c3dd5
|
||||
guid: 0f0b958b02844f940982990f3922c912
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
@@ -0,0 +1,14 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class LevelUpView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::UnityEngine.RectTransform rewardAreaRoot;
|
||||
[SerializeField] public global::SepCore.UI.LevelUpRewardItem levelUpRewardTemplate;
|
||||
[SerializeField] public global::SepCore.UI.CommonButton refreshButton;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI refreshCostFormatText;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39b4ea16f6b8d6a47b6ea7078982a7d0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,69 +0,0 @@
|
||||
using SepCore.Event;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
public class LevelUpForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private LevelUpRewardItem[] _propItems;
|
||||
|
||||
[SerializeField] private TMP_Text _refreshButtonText;
|
||||
|
||||
private LevelUpContext _context;
|
||||
|
||||
public void RefreshUI(LevelUpContext context)
|
||||
{
|
||||
_context = context;
|
||||
|
||||
foreach (var propItem in _propItems)
|
||||
{
|
||||
propItem.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
int count = Mathf.Min(_propItems.Length, _context.Props.Count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
_propItems[i].gameObject.SetActive(true);
|
||||
_propItems[i].Init(_context.Props[i]);
|
||||
}
|
||||
|
||||
//刷新 -20 <sprite name="coin" index=0>
|
||||
_refreshButtonText.text = $"刷新 -{context.RefreshPrice} <sprite name=\"coin\" index=0>";
|
||||
}
|
||||
|
||||
#region FSM
|
||||
|
||||
protected override void OnOpen(object userData)
|
||||
{
|
||||
base.OnOpen(userData);
|
||||
|
||||
if (userData is not LevelUpContext context)
|
||||
{
|
||||
Log.Error("LevelUpForm requires LevelUpContext as userData.");
|
||||
return;
|
||||
}
|
||||
|
||||
RefreshUI(context);
|
||||
}
|
||||
|
||||
protected override void OnClose(bool isShutdown, object userData)
|
||||
{
|
||||
_context = null;
|
||||
base.OnClose(isShutdown, userData);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void OnSelectButtonClick(int index)
|
||||
{
|
||||
GameEntry.Event.Fire(this, LevelUpPropSelectedEventArgs.Create(index));
|
||||
}
|
||||
|
||||
public void OnRefreshButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, LevelUpRefreshEventArgs.Create(_context.RefreshPrice));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,226 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GameFramework.ObjectPool;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
public enum DisplayListAreaType : byte
|
||||
{
|
||||
None = 0,
|
||||
Prop = 1,
|
||||
Weapon = 2
|
||||
}
|
||||
|
||||
public class DisplayListArea : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private TMP_Text _titleText;
|
||||
|
||||
[SerializeField] private TMP_Text _countText;
|
||||
|
||||
[SerializeField] private DisplayItem _displayItemTemplate;
|
||||
|
||||
[SerializeField] private Transform _displayItemRoot;
|
||||
|
||||
[SerializeField] private Vector2 _startPosition = Vector2.zero;
|
||||
|
||||
[SerializeField] private float _itemSize = 150f;
|
||||
|
||||
[SerializeField] private float _itemSpacing = 10f;
|
||||
|
||||
[SerializeField] private int _fixedColumnCount = 0;
|
||||
|
||||
[SerializeField] private int _instancePoolCapacity = 32;
|
||||
|
||||
private DisplayListAreaContext _context;
|
||||
|
||||
private IObjectPool<DisplayItemObject> _displayItemObjectPool;
|
||||
private const string DisplayItemPoolName = "DisplayItem";
|
||||
|
||||
private readonly List<DisplayItem> _activeItems = new List<DisplayItem>();
|
||||
|
||||
public void OnInit(DisplayListAreaContext context)
|
||||
{
|
||||
EnsurePool();
|
||||
_context = context;
|
||||
|
||||
_titleText.text = context.Title;
|
||||
UpdateCountText(context.CurrentCount, context.MaxCount);
|
||||
|
||||
int targetCount = Mathf.Min(context.CurrentCount, context.ItemContexts.Length);
|
||||
EnsureItemCount(targetCount);
|
||||
for (int i = 0; i < targetCount; i++)
|
||||
{
|
||||
_activeItems[i].OnInit(context.ItemContexts[i], i).Forget();
|
||||
}
|
||||
|
||||
LayoutItems();
|
||||
}
|
||||
|
||||
public void OnReset()
|
||||
{
|
||||
_context = null;
|
||||
|
||||
for (int i = _activeItems.Count - 1; i >= 0; i--)
|
||||
{
|
||||
HideItem(_activeItems[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnDestroy()
|
||||
{
|
||||
_displayItemObjectPool?.ReleaseAllUnused();
|
||||
}
|
||||
|
||||
public DisplayItem AddItem(DisplayItemContext itemContext)
|
||||
{
|
||||
EnsurePool();
|
||||
|
||||
DisplayItem item = CreateItem();
|
||||
|
||||
int index = _activeItems.Count;
|
||||
_activeItems.Add(item);
|
||||
item.OnInit(itemContext, index).Forget();
|
||||
item.SetIndex(index);
|
||||
|
||||
int columnCount = _fixedColumnCount > 0 ? _fixedColumnCount : CalculateColumnCount(GetRootWidth());
|
||||
LayoutItem(item, index, columnCount);
|
||||
|
||||
int currentCount = _activeItems.Count;
|
||||
_context.CurrentCount = currentCount;
|
||||
|
||||
UpdateCountText(currentCount, _context.MaxCount);
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
public bool RemoveItemAt(int index)
|
||||
{
|
||||
if (index < 0 || index >= _activeItems.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
HideItem(_activeItems[index]);
|
||||
LayoutItems();
|
||||
|
||||
int currentCount = _activeItems.Count;
|
||||
_context.CurrentCount = currentCount;
|
||||
|
||||
UpdateCountText(currentCount, _context.MaxCount);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void EnsurePool()
|
||||
{
|
||||
if (_displayItemObjectPool != null) return;
|
||||
|
||||
GridLayoutGroup gridLayout = _displayItemRoot.GetComponent<GridLayoutGroup>();
|
||||
if (gridLayout != null)
|
||||
{
|
||||
gridLayout.enabled = false;
|
||||
}
|
||||
|
||||
if (GameEntry.ObjectPool.HasObjectPool<DisplayItemObject>(DisplayItemPoolName))
|
||||
{
|
||||
_displayItemObjectPool = GameEntry.ObjectPool.GetObjectPool<DisplayItemObject>(DisplayItemPoolName);
|
||||
return;
|
||||
}
|
||||
|
||||
_displayItemObjectPool =
|
||||
GameEntry.ObjectPool.CreateSingleSpawnObjectPool<DisplayItemObject>(DisplayItemPoolName,
|
||||
_instancePoolCapacity);
|
||||
}
|
||||
|
||||
private void EnsureItemCount(int count)
|
||||
{
|
||||
for (int i = _activeItems.Count; i < count; i++)
|
||||
{
|
||||
_activeItems.Add(CreateItem());
|
||||
}
|
||||
|
||||
for (int i = _activeItems.Count - 1; i >= count; i--)
|
||||
{
|
||||
HideItem(_activeItems[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private DisplayItem CreateItem()
|
||||
{
|
||||
DisplayItem item;
|
||||
DisplayItemObject itemObject = _displayItemObjectPool.Spawn();
|
||||
if (itemObject != null)
|
||||
{
|
||||
item = (DisplayItem)itemObject.Target;
|
||||
}
|
||||
else
|
||||
{
|
||||
item = Instantiate(_displayItemTemplate);
|
||||
_displayItemObjectPool.Register(DisplayItemObject.Create(item), true);
|
||||
}
|
||||
|
||||
item.transform.SetParent(_displayItemRoot, false);
|
||||
item.gameObject.SetActive(true);
|
||||
return item;
|
||||
}
|
||||
|
||||
private void HideItem(DisplayItem item)
|
||||
{
|
||||
item.OnReset();
|
||||
_activeItems.Remove(item);
|
||||
item.gameObject.SetActive(false);
|
||||
_displayItemObjectPool.Unspawn(item);
|
||||
}
|
||||
|
||||
private void LayoutItems()
|
||||
{
|
||||
int columnCount = _fixedColumnCount > 0 ? _fixedColumnCount : CalculateColumnCount(GetRootWidth());
|
||||
|
||||
for (int i = 0; i < _activeItems.Count; i++)
|
||||
{
|
||||
DisplayItem item = _activeItems[i];
|
||||
item.SetIndex(i);
|
||||
LayoutItem(item, i, columnCount);
|
||||
}
|
||||
}
|
||||
|
||||
private void LayoutItem(DisplayItem item, int index, int columnCount)
|
||||
{
|
||||
RectTransform itemRect = item.GetComponent<RectTransform>();
|
||||
|
||||
float step = _itemSize + _itemSpacing;
|
||||
int row = index / columnCount;
|
||||
int col = index % columnCount;
|
||||
|
||||
itemRect.anchorMin = new Vector2(0f, 1f);
|
||||
itemRect.anchorMax = new Vector2(0f, 1f);
|
||||
itemRect.pivot = new Vector2(0f, 1f);
|
||||
itemRect.sizeDelta = new Vector2(_itemSize, _itemSize);
|
||||
itemRect.anchoredPosition = _startPosition + new Vector2(col * step, -row * step);
|
||||
}
|
||||
|
||||
private float GetRootWidth()
|
||||
{
|
||||
RectTransform rootRect = (RectTransform)_displayItemRoot;
|
||||
return rootRect.rect.width;
|
||||
}
|
||||
|
||||
private int CalculateColumnCount(float rootWidth)
|
||||
{
|
||||
if (rootWidth <= 0f) return 1;
|
||||
|
||||
float step = _itemSize + _itemSpacing;
|
||||
int columns = Mathf.FloorToInt((rootWidth + _itemSpacing) / step);
|
||||
return Mathf.Max(1, columns);
|
||||
}
|
||||
|
||||
private void UpdateCountText(int currentCount, int maxCount)
|
||||
{
|
||||
_countText.text = maxCount == -1 ? $"({currentCount})" : $"({currentCount}/{maxCount})";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
public class DisplayListAreaContext : UIContext
|
||||
{
|
||||
public string Title;
|
||||
public int CurrentCount;
|
||||
public int MaxCount = -1;
|
||||
public DisplayItemContext[] ItemContexts;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using GameFramework;
|
||||
using GameFramework.ObjectPool;
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
public class DisplayItemObject : ObjectBase
|
||||
{
|
||||
public static DisplayItemObject Create(object target)
|
||||
{
|
||||
DisplayItemObject displayItemObject = ReferencePool.Acquire<DisplayItemObject>();
|
||||
displayItemObject.Initialize(target);
|
||||
return displayItemObject;
|
||||
}
|
||||
|
||||
protected override void Release(bool isShutdown)
|
||||
{
|
||||
DisplayItem item = (DisplayItem)Target;
|
||||
if (item == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Object.Destroy(item.gameObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -8,8 +8,8 @@ namespace SepCore.UI
|
||||
public int RefreshPrice;
|
||||
public int PlayerCoin;
|
||||
public List<GoodsItemContext> GoodsItems;
|
||||
public DisplayListAreaContext PropListContext;
|
||||
public DisplayListAreaContext WeaponListContext;
|
||||
public DisplayListContext PropListContext;
|
||||
public DisplayListContext WeaponListContext;
|
||||
|
||||
// 控制字段
|
||||
public bool NeedRefreshGoodsItems;
|
||||
+12
-16
@@ -7,6 +7,13 @@ using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
public enum DisplayListAreaType : byte
|
||||
{
|
||||
None = 0,
|
||||
Prop = 1,
|
||||
Weapon = 2
|
||||
}
|
||||
|
||||
public partial class ShopController
|
||||
{
|
||||
private async UniTask<ShopContext> BuildContext(ShopRawData rawData)
|
||||
@@ -30,8 +37,8 @@ namespace SepCore.UI
|
||||
{
|
||||
GoodsItems = goodsItems,
|
||||
PropListContext =
|
||||
BuildDisplayListAreaContext(DisplayListAreaType.Prop, rawData.PropItems, rawData.PropMaxCount),
|
||||
WeaponListContext = BuildDisplayListAreaContext(DisplayListAreaType.Weapon, rawData.WeaponItems,
|
||||
BuildDisplayListContext(DisplayListAreaType.Prop, rawData.PropItems, rawData.PropMaxCount),
|
||||
WeaponListContext = BuildDisplayListContext(DisplayListAreaType.Weapon, rawData.WeaponItems,
|
||||
rawData.WeaponMaxCount),
|
||||
NeedRefreshGoodsItems = true,
|
||||
NeedRefreshPlayerCoin = true,
|
||||
@@ -41,7 +48,7 @@ namespace SepCore.UI
|
||||
};
|
||||
}
|
||||
|
||||
private static DisplayListAreaContext BuildDisplayListAreaContext(DisplayListAreaType listType,
|
||||
private static DisplayListContext BuildDisplayListContext(DisplayListAreaType listType,
|
||||
IReadOnlyList<object> items, int maxCount)
|
||||
{
|
||||
DisplayItemContext[] itemContexts = new DisplayItemContext[items.Count];
|
||||
@@ -66,25 +73,14 @@ namespace SepCore.UI
|
||||
break;
|
||||
}
|
||||
|
||||
return new DisplayListAreaContext
|
||||
return new DisplayListContext
|
||||
{
|
||||
Title = GetDisplayListTitle(listType),
|
||||
CurrentCount = itemContexts.Length,
|
||||
MaxCount = maxCount,
|
||||
ItemContexts = itemContexts
|
||||
};
|
||||
}
|
||||
|
||||
private static string GetDisplayListTitle(DisplayListAreaType listType)
|
||||
{
|
||||
return listType switch
|
||||
{
|
||||
DisplayListAreaType.Weapon => "武器",
|
||||
DisplayListAreaType.Prop => "道具",
|
||||
_ => string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
private static DisplayItemContext BuildPropItem(PropItem propItem)
|
||||
{
|
||||
return new DisplayItemContext
|
||||
@@ -105,7 +101,7 @@ namespace SepCore.UI
|
||||
};
|
||||
}
|
||||
|
||||
private static void AppendDisplayItemContext(DisplayListAreaContext listContext, DisplayItemContext newItem)
|
||||
private static void AppendDisplayItemContext(DisplayListContext listContext, DisplayItemContext newItem)
|
||||
{
|
||||
int oldCount = listContext.ItemContexts.Length;
|
||||
DisplayItemContext[] newContexts = new DisplayItemContext[oldCount + 1];
|
||||
+69
-73
@@ -1,115 +1,56 @@
|
||||
using System.Collections.Generic;
|
||||
using SepCore.Event;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
public class ShopForm : UGuiForm
|
||||
public partial class ShopForm : UGuiForm
|
||||
{
|
||||
#region Property
|
||||
|
||||
[SerializeField] private TMP_Text _titleText;
|
||||
|
||||
[SerializeField] private TMP_Text _continueButtonText;
|
||||
|
||||
[SerializeField] private TMP_Text _refreshPriceText;
|
||||
|
||||
[SerializeField] private TMP_Text _playerCoinText;
|
||||
|
||||
[SerializeField] private ShopGoodsItem[] _goodsItems;
|
||||
|
||||
[SerializeField] private DisplayListArea _propListArea;
|
||||
|
||||
[SerializeField] private DisplayListArea _weaponListArea;
|
||||
private readonly List<ShopGoodsItem> _goodsItems = new List<ShopGoodsItem>();
|
||||
|
||||
private ShopContext _context;
|
||||
|
||||
#endregion
|
||||
|
||||
private bool _listenersBound;
|
||||
|
||||
public void RefreshUI(ShopContext context)
|
||||
{
|
||||
EnsureButtonListeners();
|
||||
|
||||
_context = context;
|
||||
|
||||
// 首次打开或需要全量刷新时
|
||||
if (context.NeedRefreshGoodsItems)
|
||||
{
|
||||
_titleText.text = $"商店 (Lv.{context.CurrentLevel})";
|
||||
_continueButtonText.text = $"继续 (Lv.{context.CurrentLevel + 1})";
|
||||
View.titleFormatText.Set(context.CurrentLevel);
|
||||
View.continueButtonFormatText.Set(context.CurrentLevel + 1);
|
||||
RefreshGoodsItems(context.GoodsItems);
|
||||
context.NeedRefreshGoodsItems = false;
|
||||
}
|
||||
|
||||
if (context.NeedRefreshPrice)
|
||||
{
|
||||
RefreshRefreshPrice(context.RefreshPrice);
|
||||
View.refreshButtonFormatText.Set(context.RefreshPrice);
|
||||
context.NeedRefreshPrice = false;
|
||||
}
|
||||
|
||||
if (context.NeedRefreshPlayerCoin)
|
||||
{
|
||||
_playerCoinText.text = $"<sprite name=\"coin\"> {context.PlayerCoin}";
|
||||
View.playerCoinFormatText.Set(context.PlayerCoin);
|
||||
context.NeedRefreshPlayerCoin = false;
|
||||
}
|
||||
|
||||
if (context.NeedRefreshPropList)
|
||||
{
|
||||
_propListArea.OnInit(context.PropListContext);
|
||||
View.propList.OnInit(context.PropListContext);
|
||||
context.NeedRefreshPropList = false;
|
||||
}
|
||||
|
||||
if (context.NeedRefreshWeaponList)
|
||||
{
|
||||
_weaponListArea.OnInit(context.WeaponListContext);
|
||||
View.weaponList.OnInit(context.WeaponListContext);
|
||||
context.NeedRefreshWeaponList = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshGoodsItems(List<GoodsItemContext> goodsItems)
|
||||
{
|
||||
foreach (var item in _goodsItems)
|
||||
{
|
||||
item.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
int count = Mathf.Min(_goodsItems.Length, goodsItems.Count);
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
if (goodsItems[i] == null) continue;
|
||||
|
||||
_goodsItems[i].Init(goodsItems[i]);
|
||||
_goodsItems[i].gameObject.SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshRefreshPrice(int refreshPrice)
|
||||
{
|
||||
_refreshPriceText.text = $"刷新 -{refreshPrice} <sprite name=\"coin\">";
|
||||
}
|
||||
|
||||
#region ButtonClick
|
||||
|
||||
public void OnContinueButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, ShopContinueEventArgs.Create());
|
||||
}
|
||||
|
||||
public void OnPurchaseButtonClick(int index)
|
||||
{
|
||||
GameEntry.Event.Fire(this, ShopPurchaseEventArgs.Create(index));
|
||||
}
|
||||
|
||||
public void OnRefreshButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, ShopRefreshEventArgs.Create(_context.RefreshPrice));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region FSM
|
||||
|
||||
protected override void OnOpen(object userData)
|
||||
{
|
||||
base.OnOpen(userData);
|
||||
@@ -127,12 +68,67 @@ namespace SepCore.UI
|
||||
{
|
||||
_context = null;
|
||||
|
||||
_propListArea.OnReset();
|
||||
_weaponListArea.OnReset();
|
||||
for (int i = 0; i < _goodsItems.Count; i++)
|
||||
{
|
||||
_goodsItems[i].OnReset();
|
||||
}
|
||||
|
||||
View.propList.OnReset();
|
||||
View.weaponList.OnReset();
|
||||
|
||||
base.OnClose(isShutdown, userData);
|
||||
}
|
||||
|
||||
#endregion
|
||||
private void EnsureButtonListeners()
|
||||
{
|
||||
if (_listenersBound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_listenersBound = true;
|
||||
|
||||
View.continueButton.onClick.AddListener(OnContinueButtonClick);
|
||||
View.refreshButton.onClick.AddListener(OnRefreshButtonClick);
|
||||
}
|
||||
|
||||
private void RefreshGoodsItems(List<GoodsItemContext> goodsItems)
|
||||
{
|
||||
EnsureGoodsItemCount(goodsItems.Count);
|
||||
|
||||
for (int i = 0; i < _goodsItems.Count; i++)
|
||||
{
|
||||
ShopGoodsItem item = _goodsItems[i];
|
||||
if (i < goodsItems.Count && goodsItems[i] != null)
|
||||
{
|
||||
item.Init(goodsItems[i], i);
|
||||
item.gameObject.SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
item.OnReset();
|
||||
item.gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureGoodsItemCount(int count)
|
||||
{
|
||||
while (_goodsItems.Count < count)
|
||||
{
|
||||
ShopGoodsItem item = Instantiate(View.goodsItemTemplate, View.GoodsItemRoot);
|
||||
_goodsItems.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnContinueButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, ShopContinueEventArgs.Create());
|
||||
}
|
||||
|
||||
public void OnRefreshButtonClick()
|
||||
{
|
||||
GameEntry.Event.Fire(this, ShopRefreshEventArgs.Create(_context.RefreshPrice));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class ShopForm : UGuiForm
|
||||
{
|
||||
[SerializeField] private ShopView _view = null;
|
||||
|
||||
public ShopView View => _view;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b261ad08be35724a83c21227db57e6b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+40
-8
@@ -1,26 +1,32 @@
|
||||
using System;
|
||||
using SepCore.Event;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
public class ShopGoodsItem : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private IconArea _iconArea;
|
||||
|
||||
|
||||
[SerializeField] private TMP_Text _titleText;
|
||||
|
||||
|
||||
[SerializeField] private TMP_Text _typeText;
|
||||
|
||||
|
||||
[SerializeField] private TMP_Text _descriptionText;
|
||||
|
||||
|
||||
[SerializeField] private TMP_Text _costText;
|
||||
|
||||
#region Init
|
||||
private int _index = -1;
|
||||
|
||||
public void Init(GoodsItemContext data)
|
||||
private bool _listenersBound;
|
||||
|
||||
public void Init(GoodsItemContext data, int index)
|
||||
{
|
||||
EnsureListeners();
|
||||
|
||||
_index = index;
|
||||
|
||||
_iconArea.OnInit(data.Icon, data.Rarity);
|
||||
_titleText.text = data.Name;
|
||||
_typeText.text = data.ItemType switch
|
||||
@@ -34,6 +40,32 @@ namespace SepCore.UI
|
||||
_costText.text = $"{data.Price} <sprite name=\"coin\" index=0>";
|
||||
}
|
||||
|
||||
#endregion
|
||||
public void OnReset()
|
||||
{
|
||||
_index = -1;
|
||||
}
|
||||
|
||||
private void EnsureListeners()
|
||||
{
|
||||
if (_listenersBound)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_listenersBound = true;
|
||||
|
||||
CommonButton button = GetComponentInChildren<CommonButton>(true);
|
||||
button.onClick.AddListener(OnPurchaseClick);
|
||||
}
|
||||
|
||||
private void OnPurchaseClick()
|
||||
{
|
||||
if (_index < 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Fire(this, ShopPurchaseEventArgs.Create(_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// <auto-generated />
|
||||
using UnityEngine;
|
||||
|
||||
namespace SepCore.UI
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public partial class ShopView : MonoBehaviour
|
||||
{
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI titleFormatText;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI playerCoinFormatText;
|
||||
[SerializeField] public global::SepCore.UI.CommonButton refreshButton;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI refreshButtonFormatText;
|
||||
[SerializeField] public global::UnityEngine.RectTransform GoodsItemRoot;
|
||||
[SerializeField] public global::SepCore.UI.ShopGoodsItem goodsItemTemplate;
|
||||
[SerializeField] public global::SepCore.UI.CommonButton continueButton;
|
||||
[SerializeField] public global::SepCore.UI.FormatTextUI continueButtonFormatText;
|
||||
[SerializeField] public global::SepCore.UI.DisplayListForm weaponList;
|
||||
[SerializeField] public global::SepCore.UI.DisplayListForm propList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 10a546b2f753668479061813a7f5781f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -20,6 +20,7 @@ namespace SepCore.CustomComponent
|
||||
{
|
||||
"tbenemyconfig",
|
||||
"tbentityconfig",
|
||||
"tbformattext",
|
||||
"tbglobalconfig",
|
||||
"tbgoodsconfig",
|
||||
"tblevelconfig",
|
||||
@@ -57,6 +58,11 @@ namespace SepCore.CustomComponent
|
||||
StringAccessor(tables => key => tables.TbEntityConfig.GetOrDefault(key),
|
||||
tables => tables.TbEntityConfig.DataList)
|
||||
},
|
||||
{
|
||||
typeof(FormatText),
|
||||
StringAccessor(tables => key => tables.TbFormatText.GetOrDefault(key),
|
||||
tables => tables.TbFormatText.DataList)
|
||||
},
|
||||
{
|
||||
typeof(GoodsConfig),
|
||||
Accessor(tables => id => tables.TbGoodsConfig.GetOrDefault(id),
|
||||
@@ -165,7 +171,7 @@ namespace SepCore.CustomComponent
|
||||
public bool IsReady => Tables != null;
|
||||
|
||||
public TbGlobalConfig Global => Tables.TbGlobalConfig;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 按 id 获取数据行,未找到时返回 null。
|
||||
/// </summary>
|
||||
@@ -191,6 +197,7 @@ namespace SepCore.CustomComponent
|
||||
{
|
||||
return (T)accessor.StringRowGetter(Tables, id.ToString());
|
||||
}
|
||||
|
||||
throw new NotSupportedException("Table for type '" + typeof(T).FullName + "' does not use an int key.");
|
||||
}
|
||||
|
||||
@@ -222,7 +229,9 @@ namespace SepCore.CustomComponent
|
||||
{
|
||||
return (T)accessor.RowGetter(Tables, parsedId);
|
||||
}
|
||||
throw new NotSupportedException("Table for type '" + typeof(T).FullName + "' does not use a string key.");
|
||||
|
||||
throw new NotSupportedException(
|
||||
"Table for type '" + typeof(T).FullName + "' does not use a string key.");
|
||||
}
|
||||
|
||||
return (T)accessor.StringRowGetter(Tables, key);
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7af0b9398035e254cb6de37a6c301552
|
||||
guid: f228612923ff51343a4dab06ce4c1f92
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 166c0ae58c1d0b34ababe6d3a3791efa
|
||||
guid: 8e4010de30b33144fa20400058edfeba
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b12df2039d69e14aa018b259f3789cf
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35c8961f073eae8479506bdec8b745f8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user