功能:添加启动器场景并更新项目设置

- 调整了启动器场景名(Assets/Launcher.unity)及对应的元数据文件。
- 添加了README.md项目文档,包含安装说明、项目结构、编码规范、测试指南及依赖项。
This commit is contained in:
SepComet
2026-02-13 21:49:59 +08:00
parent 88641dae11
commit d650dd63e7
55 changed files with 1136 additions and 161 deletions
@@ -0,0 +1,34 @@
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace UI
{
public class GoodsItem : MonoBehaviour
{
[SerializeField] private Image _iconImage;
[SerializeField] private TMP_Text _titleText;
[SerializeField] private TMP_Text _typeText;
[SerializeField] private TMP_Text _descriptionText;
[SerializeField] private TMP_Text _costText;
[SerializeField] private CommonButton _purchaseButton;
#region Init
public void Init(GoodsItemContext data)
{
_iconImage.sprite = data.Icon;
_titleText.text = data.Title;
_typeText.text = data.Type;
_descriptionText.text = data.Description;
_costText.text = data.Price.ToString();
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 271f2a0727c521c4280eb2d47fd8de33
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,103 @@
using Components;
using CustomEvent;
using Entity;
using GameFramework.Event;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace UI
{
public class HudForm : UGuiForm
{
[SerializeField] private float _sliderFadeDuration = 0.5f;
[SerializeField] private Slider _hpSlider;
private float _currentHpPercent = 0;
private Coroutine _hpSliderFadeCoroutine;
[SerializeField] private Slider _expSlider;
private float _currentExpPercent = 0;
private Coroutine _expSliderFadeCoroutine;
[SerializeField] private TMP_Text _coinText;
private int _currentCoin = 0;
#region FSM
protected override void OnInit(object userData)
{
base.OnInit(userData);
GameEntry.Event.Subscribe(PlayerHealthChangeEventArgs.EventId, OnPlayerHpChange);
GameEntry.Event.Subscribe(PlayerExpChangeEventArgs.EventId, OnPlayerExpChange);
GameEntry.Event.Subscribe(PlayerCoinChangeEventArgs.EventId, OnPlayerCoinChange);
}
protected override void OnClose(bool isShutdown, object userData)
{
GameEntry.Event.Unsubscribe(PlayerHealthChangeEventArgs.EventId, OnPlayerHpChange);
GameEntry.Event.Unsubscribe(PlayerExpChangeEventArgs.EventId, OnPlayerExpChange);
GameEntry.Event.Unsubscribe(PlayerCoinChangeEventArgs.EventId, OnPlayerCoinChange);
base.OnClose(isShutdown, userData);
}
#endregion
#region Event Handlers
private void OnPlayerHpChange(object sender, GameEventArgs e)
{
if (!(e is PlayerHealthChangeEventArgs args)) return;
float percent = (float)args.CurrentHealth / args.MaxHealth;
if (Mathf.Approximately(_currentHpPercent, percent)) return;
_currentHpPercent = percent;
if (_hpSliderFadeCoroutine != null) StopCoroutine(_hpSliderFadeCoroutine);
_hpSliderFadeCoroutine = StartCoroutine(_hpSlider.SmoothValue(percent, _sliderFadeDuration));
}
private void OnPlayerExpChange(object sender, GameEventArgs e)
{
if (!(e is PlayerExpChangeEventArgs args)) return;
float percent = (float)args.CurrentExp / args.MaxExp;
if (Mathf.Approximately(_currentExpPercent, percent)) return;
_currentExpPercent = percent;
if (_expSliderFadeCoroutine != null) StopCoroutine(_expSliderFadeCoroutine);
_expSliderFadeCoroutine = StartCoroutine(_expSlider.SmoothValue(percent, _sliderFadeDuration));
}
private void OnPlayerCoinChange(object sender, GameEventArgs e)
{
if (!(e is PlayerCoinChangeEventArgs args)) return;
if (_currentCoin == args.CoinCount) return;
_coinText.text = args.CoinCount.ToString();
_currentCoin = args.CoinCount;
}
#endregion
#region Test
private Player _player;
public void CauseDamageToPlayer()
{
if (_player == null)
{
_player = FindObjectOfType<Player>();
}
if (_player == null) return;
_player.GetComponent<HealthComponent>().TakeDamage(2);
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bd4c4d6e8d4b0f54c830e2cfef46848e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,66 @@
using CustomEvent;
using TMPro;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace UI
{
public class LevelUpForm : UGuiForm
{
[SerializeField] private TMP_Text _titleText;
[SerializeField] private LevelUpPropItem[] _propItems;
private LevelUpFormContext _context;
public void RefreshUI(LevelUpFormContext context)
{
_context = context;
if (_titleText != null)
{
_titleText.text = $"Level Up (Lv.{_context.Level})";
}
foreach (var propItem in _propItems)
{
propItem.gameObject.SetActive(false);
}
if (_context.Props == null) return;
for (int i = 0; i < _propItems.Length; i++)
{
_propItems[i].gameObject.SetActive(true);
_propItems[i].Init(_context.Props[i]);
}
}
#region FSM
protected override void OnOpen(object userData)
{
base.OnOpen(userData);
if (userData is LevelUpFormContext context)
{
RefreshUI(context);
return;
}
Log.Warning("LevelUpForm requires LevelUpFormContext as userData.");
}
protected override void OnClose(bool isShutdown, object userData)
{
_context = null;
base.OnClose(isShutdown, userData);
}
#endregion
private void OnSelectProp(int index)
{
GameEntry.Event.Fire(this, LevelUpPropSelectedEventArgs.Create(index));
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 73f52c8a6d8b8ec42ad8cd3c00e0254d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,50 @@
using System;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using UnityGameFramework.Runtime;
namespace UI
{
public class LevelUpPropItem : MonoBehaviour
{
[SerializeField] private Image _iconImage;
[SerializeField] private TMP_Text _titleText;
[SerializeField] private TMP_Text _typeText;
[SerializeField] private TMP_Text _descriptionText;
private LevelUpPropContext _context;
public void Init(LevelUpPropContext context)
{
if (context == null)
{
Log.Error("LevelUpPropContext context is invalid.");
return;
}
_context = context;
if (_titleText != null) _titleText.text = context.Title;
if (_typeText != null) _typeText.text = context.Type;
if (_descriptionText != null) _descriptionText.text = context.Description;
if (_iconImage != null) _iconImage.sprite = context.Icon;
LoadIcon(_context.IconAssetName);
}
private void LoadIcon(string iconAssetName)
{
if (_iconImage == null) return;
if (string.IsNullOrEmpty(iconAssetName)) return;
GameEntry.SpriteCache.GetSprite(iconAssetName, sprite => _iconImage.sprite = sprite);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 237d64392d274c14f9f5c81b54122a93
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,110 @@
using CustomEvent;
using GameFramework.Event;
using TMPro;
using UnityEngine;
namespace UI
{
public 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;
private int _currentCoin;
[SerializeField] private GoodsItem[] _goodsItems;
private ShopFormContext _context;
#endregion
public void RefreshUI(ShopFormContext context)
{
_context = context;
_titleText.text = $"商店 (Lv.{context.CurrentLevel})";
_continueButtonText.text = $"继续 (Lv.{context.CurrentLevel + 1})";
_refreshPriceText.text = $"-{context.RefreshPrice}";
_playerCoinText.text = context.PlayerCoin.ToString();
foreach (var item in _goodsItems)
{
item.gameObject.SetActive(false);
}
if (_context.GoodsItems == null) return;
for (int i = 0; i < _context.GoodsItems.Count; i++)
{
_goodsItems[i].Init(context.GoodsItems[i]);
_goodsItems[i].gameObject.SetActive(true);
}
}
#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);
GameEntry.Event.Subscribe(PlayerCoinChangeEventArgs.EventId, OnPlayerCoinChange);
if (userData is ShopFormContext context)
{
RefreshUI(context);
return;
}
UnityGameFramework.Runtime.Log.Warning("ShopForm requires ShopFormContext as userData.");
}
protected override void OnClose(bool isShutdown, object userData)
{
_context = null;
GameEntry.Event.Unsubscribe(PlayerCoinChangeEventArgs.EventId, OnPlayerCoinChange);
base.OnClose(isShutdown, userData);
}
#endregion
#region Event Handlers
private void OnPlayerCoinChange(object sender, GameEventArgs e)
{
if (!(e is PlayerCoinChangeEventArgs args)) return;
if (args.CoinCount == _currentCoin) return;
_currentCoin = args.CoinCount;
_playerCoinText.text = _currentCoin.ToString();
}
#endregion
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a6f22432e5701804d9a78d0c07f4c334
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: