| | |
| | | using UnityEngine.UI; |
| | | using DG.Tweening; |
| | | using Cysharp.Threading.Tasks; |
| | | |
| | | using System; |
| | | using LitJson; |
| | | |
| | | // 这个界面是 persistent的界面 |
| | | public class BattleHUDWin : UIBase |
| | | { |
| | | // 组件引用 |
| | | // private List<HUDContent> damageList = new List<HUDContent>(); |
| | | |
| | | // private List<BuffContent> buffList = new List<BuffContent>(); |
| | | private const int CASTER_DAMAGE_HEIGHT_OFFSET = 100; // 施法者伤害高度间隔 |
| | | private const int CASTER_DAMAGE_FLOAT_HEIGHT = 150; // 飘字向上移动高度 |
| | | private const int TARGET_DAMAGE_FLOAT_HEIGHT = 150; // 目标伤害飘字向上移动高度 |
| | | |
| | | private GameObjectPoolManager.GameObjectPool damagePrefabPool; |
| | | |
| | | private GameObjectPoolManager.GameObjectPool buffIconPrefabPool; |
| | | |
| | | private GameObjectPoolManager.GameObjectPool buffLabelPrefabPool; |
| | | |
| | | public Transform damageNode; |
| | | |
| | | public Transform buffIconNode; |
| | | |
| | | public Transform buffLabelNode; |
| | | |
| | | private BattleField battleField; |
| | | |
| | | private List<DamageContent> damageContentList = new List<DamageContent>(); |
| | | |
| | | // 生命周期 |
| | | protected override void InitComponent() |
| | | { |
| | | base.InitComponent(); |
| | | // 初始化组件引用 绑定按钮等UI组件事件 |
| | | } |
| | | |
| | | protected override void OnPreOpen() |
| | | { |
| | | base.OnPreOpen(); |
| | | EventBroadcast.Instance.AddListener<string, BattleObject, List<long>>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken); |
| | | EventBroadcast.Instance.AddListener<BattleObject, SkillConfig>(EventName.BATTLE_BUFF_MOUNTED, OnBuffMounted); |
| | | EventBroadcast.Instance.AddListener<BattleObject, SkillConfig>(EventName.BATTLE_BUFF_DISAPEAR, OnBuffDisapear); |
| | | damagePrefabPool = GameObjectPoolManager.Instance.RequestPool(ResManager.Instance.LoadAsset<GameObject>("UIComp", "DamageContent")); |
| | | // buffIconPrefabPool = GameObjectPoolManager.Instance.RequestPool(); |
| | | // buffLabelPrefabPool = GameObjectPoolManager.Instance.RequestPool(ResManager.Instance.LoadAsset<GameObject>("UIComp", "BuffContent")); |
| | | RegisterEvents(); |
| | | InitializePools(); |
| | | } |
| | | |
| | | protected override void OnPreClose() |
| | | { |
| | | base.OnPreClose(); |
| | | EventBroadcast.Instance.RemoveListener<string, BattleObject, List<long>>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken); |
| | | EventBroadcast.Instance.RemoveListener<BattleObject, SkillConfig>(EventName.BATTLE_BUFF_MOUNTED, OnBuffMounted); |
| | | EventBroadcast.Instance.RemoveListener<BattleObject, SkillConfig>(EventName.BATTLE_BUFF_DISAPEAR, OnBuffDisapear); |
| | | UnregisterEvents(); |
| | | } |
| | | |
| | | protected override void OnOpen() |
| | |
| | | protected override void OnClose() |
| | | { |
| | | base.OnClose(); |
| | | battleField.OnBattlePause -= OnBattlePause; |
| | | battleField = null; |
| | | CleanupBattleField(); |
| | | } |
| | | |
| | | protected override void NextFrameAfterOpen() |
| | |
| | | base.CompleteClose(); |
| | | } |
| | | |
| | | private void RemoveDamageContent(DamageContent content) |
| | | private void RegisterEvents() |
| | | { |
| | | damageContentList.Remove(content); |
| | | damagePrefabPool.Release(content.gameObject); |
| | | EventBroadcast.Instance.AddListener<BattleDmgInfo>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken); |
| | | EventBroadcast.Instance.AddListener<string, JsonData>(EventName.BATTLE_END, OnBattleEnd); |
| | | } |
| | | |
| | | private void OnDamageTaken(string guid, BattleObject bo, List<long> damageList) |
| | | private void UnregisterEvents() |
| | | { |
| | | GameObject damageContent = damagePrefabPool.Request(); |
| | | DamageContent content = damageContent.GetComponent<DamageContent>(); |
| | | damageContent.transform.SetParent(damageNode, false); |
| | | damageContent.transform.localPosition = new Vector3(damageContent.transform.localPosition.x, damageContent.transform.localPosition.y, 0); |
| | | content.SetDamage(damageList, () => RemoveDamageContent(content)); |
| | | damageContentList.Add(content); |
| | | EventBroadcast.Instance.RemoveListener<BattleDmgInfo>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken); |
| | | EventBroadcast.Instance.RemoveListener<string, JsonData>(EventName.BATTLE_END, OnBattleEnd); |
| | | } |
| | | |
| | | // heroGo 的 parent 作为参考节点 |
| | | var heroGo = bo.heroGo; |
| | | if (heroGo == null) |
| | | return; |
| | | private void InitializePools() |
| | | { |
| | | damagePrefabPool = GameObjectPoolManager.Instance.GetPool(UILoader.LoadPrefab("DamageContent")); |
| | | } |
| | | |
| | | var heroRect = heroGo.GetComponent<RectTransform>(); |
| | | if (heroRect == null) |
| | | return; |
| | | public void SetBattleField(BattleField _battleField) |
| | | { |
| | | CleanupBattleField(); |
| | | ClearContent(string.Empty, true); |
| | | |
| | | battleField = _battleField; |
| | | RegisterBattleFieldEvents(); |
| | | } |
| | | |
| | | // 计算 heroGo 在 content 父节点下的 anchoredPosition |
| | | var contentRect = content.GetComponent<RectTransform>(); |
| | | var contentParentRect = contentRect.parent as RectTransform; |
| | | private void RegisterBattleFieldEvents() |
| | | { |
| | | if (battleField == null) return; |
| | | |
| | | battleField.OnBattlePause += OnBattlePause; |
| | | battleField.OnBattleRun += OnBattleRun; |
| | | battleField.OnSpeedRatioChange += OnSpeedRatioChange; |
| | | } |
| | | |
| | | // 获取 heroGo 的世界坐标 |
| | | Vector3 worldTargetPos = heroRect.TransformPoint(heroRect.anchoredPosition); |
| | | private void UnregisterBattleFieldEvents() |
| | | { |
| | | if (battleField == null) return; |
| | | |
| | | battleField.OnBattlePause -= OnBattlePause; |
| | | battleField.OnBattleRun -= OnBattleRun; |
| | | battleField.OnSpeedRatioChange -= OnSpeedRatioChange; |
| | | } |
| | | |
| | | // 转换到 content 父节点下的 anchoredPosition |
| | | private void CleanupBattleField() |
| | | { |
| | | UnregisterBattleFieldEvents(); |
| | | battleField = null; |
| | | } |
| | | |
| | | private void OnBattleEnd(string guid, JsonData data) |
| | | { |
| | | ClearContent(guid); |
| | | } |
| | | |
| | | private void OnDamageTaken(BattleDmgInfo damageInfo) |
| | | { |
| | | SetTargetDamage(damageInfo); |
| | | SetSelfDamage(damageInfo); |
| | | } |
| | | |
| | | private void OnSpeedRatioChange(float newSpeedRatio) |
| | | { |
| | | foreach (var content in damageContentList) |
| | | { |
| | | content.SetRatio(newSpeedRatio, 1f); |
| | | } |
| | | } |
| | | |
| | | private void OnBattlePause(bool isPause) |
| | | { |
| | | if (isPause) |
| | | { |
| | | PauseAllDamageContent(); |
| | | } |
| | | else |
| | | { |
| | | ResumeAllDamageContent(); |
| | | } |
| | | } |
| | | |
| | | private void OnBattleRun() |
| | | { |
| | | RunAllDamageContent(); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 设置目标受到的伤害显示 |
| | | /// </summary> |
| | | private void SetTargetDamage(BattleDmgInfo damageInfo) |
| | | { |
| | | if (damageInfo.targetDamageList.Count == 0) return; |
| | | |
| | | RectTransform heroRect = damageInfo.hurtObj.heroRectTrans; |
| | | if (heroRect == null) return; |
| | | |
| | | DamageContent content = CreateDamageContent(); |
| | | if (content == null) return; |
| | | |
| | | Vector2 anchoredPos = CalculateWorldToLocalPosition(heroRect, content); |
| | | SetupTargetDamagePosition(content, anchoredPos); |
| | | SetupDamageContent(content, damageInfo.targetDamageList, damageInfo); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 设置目标伤害的起始和结束位置 |
| | | /// </summary> |
| | | private void SetupTargetDamagePosition(DamageContent content, Vector2 anchoredPos) |
| | | { |
| | | // 保持英雄的 X 坐标,只在 Y 轴向上飘 |
| | | Vector2 beginPos = anchoredPos; |
| | | Vector2 endPos = anchoredPos + new Vector2(0, TARGET_DAMAGE_FLOAT_HEIGHT); |
| | | content.SetPosition(beginPos, endPos); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 设置施法者受到的伤害显示(反伤、吸血等) |
| | | /// </summary> |
| | | private void SetSelfDamage(BattleDmgInfo damageInfo) |
| | | { |
| | | if (damageInfo.casterDamageList.Count == 0) return; |
| | | |
| | | RectTransform heroRect = damageInfo.casterObj.heroRectTrans; |
| | | if (heroRect == null) return; |
| | | |
| | | // 创建单个DamageContent显示所有施法者伤害 |
| | | DamageContent content = CreateDamageContent(); |
| | | if (content == null) return; |
| | | |
| | | Vector2 anchoredPos = CalculateWorldToLocalPosition(heroRect, content); |
| | | SetupCasterDamagePosition(content, anchoredPos); |
| | | SetupDamageContent(content, damageInfo.casterDamageList, damageInfo); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 设置施法者伤害的起始和结束位置 |
| | | /// </summary> |
| | | private void SetupCasterDamagePosition(DamageContent content, Vector2 anchoredPos) |
| | | { |
| | | // 保持英雄的 X 坐标,只在 Y 轴向上飘 |
| | | Vector2 beginPos = anchoredPos; |
| | | Vector2 endPos = anchoredPos + new Vector2(0, CASTER_DAMAGE_FLOAT_HEIGHT); |
| | | content.SetPosition(beginPos, endPos); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 创建一个DamageContent对象 |
| | | /// </summary> |
| | | private DamageContent CreateDamageContent() |
| | | { |
| | | GameObject damageContentObj = damagePrefabPool.Request(); |
| | | DamageContent content = damageContentObj.GetComponent<DamageContent>(); |
| | | damageContentObj.transform.SetParent(damageNode, false); |
| | | return content; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 计算英雄世界坐标到本地坐标的转换 |
| | | /// </summary> |
| | | private Vector2 CalculateWorldToLocalPosition(RectTransform heroRect, DamageContent content) |
| | | { |
| | | RectTransform contentRect = content.GetComponent<RectTransform>(); |
| | | RectTransform contentParentRect = contentRect.parent as RectTransform; |
| | | |
| | | Vector3 worldTargetPos = heroRect.transform.TransformPoint(heroRect.rect.center); |
| | | |
| | | Vector2 anchoredPos; |
| | | RectTransformUtility.ScreenPointToLocalPointInRectangle( |
| | | contentParentRect, |
| | |
| | | null, |
| | | out anchoredPos); |
| | | |
| | | contentRect.anchoredPosition = anchoredPos; |
| | | return anchoredPos; |
| | | } |
| | | |
| | | private void OnBuffMounted(BattleObject bo, SkillConfig buffConfig) |
| | | { |
| | | |
| | | } |
| | | |
| | | private void OnBuffDisapear(BattleObject bo, SkillConfig buffConfig) |
| | | { |
| | | |
| | | } |
| | | |
| | | public void SetBattleField(BattleField _battleField) |
| | | /// <summary> |
| | | /// 配置DamageContent的速度、伤害数据和回调 |
| | | /// </summary> |
| | | private void SetupDamageContent(DamageContent content, List<BattleDmg> damageList, BattleDmgInfo damageInfo) |
| | | { |
| | | if (battleField != null) |
| | | { |
| | | battleField.OnBattlePause -= OnBattlePause; |
| | | content.SetRatio(battleField.speedRatio, 1f); |
| | | } |
| | | |
| | | battleField = _battleField; |
| | | battleField.OnBattlePause += OnBattlePause; |
| | | content.SetDamage(damageInfo, damageList, () => RemoveDamageContent(content)); |
| | | damageContentList.Add(content); |
| | | } |
| | | |
| | | private void OnBattlePause(bool isPause) |
| | | /// <summary> |
| | | /// 移除DamageContent对象 |
| | | /// </summary> |
| | | private void RemoveDamageContent(DamageContent content) |
| | | { |
| | | // 游戏暂停 |
| | | if (isPause) |
| | | damageContentList.Remove(content); |
| | | damagePrefabPool.Release(content.gameObject); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 清除所有伤害显示内容 |
| | | /// </summary> |
| | | private void ClearContent(string guid, bool force = false) |
| | | { |
| | | if ((battleField != null && battleField.guid == guid) || force) |
| | | { |
| | | foreach (var content in damageContentList) |
| | | for (int i = damageContentList.Count - 1; i >= 0; i--) |
| | | { |
| | | var content = damageContentList[i]; |
| | | content.Stop(); |
| | | RemoveDamageContent(content); |
| | | } |
| | | damageContentList.Clear(); |
| | | } |
| | | // 游戏恢复 |
| | | else |
| | | } |
| | | |
| | | private void PauseAllDamageContent() |
| | | { |
| | | foreach (var content in damageContentList) |
| | | { |
| | | foreach (var content in damageContentList) |
| | | content.Stop(); |
| | | } |
| | | } |
| | | |
| | | private void ResumeAllDamageContent() |
| | | { |
| | | foreach (var content in damageContentList) |
| | | { |
| | | content.Resume(); |
| | | } |
| | | } |
| | | |
| | | private void RunAllDamageContent() |
| | | { |
| | | for (int i = damageContentList.Count - 1; i >= 0; i--) |
| | | { |
| | | if (i < damageContentList.Count) |
| | | { |
| | | content.Resume(); |
| | | damageContentList[i].Run(); |
| | | } |
| | | } |
| | | } |