| | |
| | | // 这个界面是 persistent的界面 |
| | | public class BattleHUDWin : UIBase |
| | | { |
| | | 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; |
| | |
| | | protected override void OnPreOpen() |
| | | { |
| | | base.OnPreOpen(); |
| | | EventBroadcast.Instance.AddListener<BattleDmgInfo>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken); |
| | | EventBroadcast.Instance.AddListener<string, JsonData>(EventName.BATTLE_END, OnBattleEnd); |
| | | damagePrefabPool = GameObjectPoolManager.Instance.RequestPool(UILoader.LoadPrefab("DamageContent")); |
| | | } |
| | | |
| | | private void OnBattleEnd(string guid, JsonData data) |
| | | { |
| | | ClearContent(guid); |
| | | } |
| | | |
| | | private void ClearContent(string guid, bool force = false) |
| | | { |
| | | if ((battleField != null && battleField.guid == guid) || force) |
| | | { |
| | | for (int i = damageContentList.Count - 1; i >= 0; i--) |
| | | { |
| | | var content = damageContentList[i]; |
| | | content.Stop(); |
| | | RemoveDamageContent(content); |
| | | } |
| | | damageContentList.Clear(); |
| | | } |
| | | RegisterEvents(); |
| | | InitializePools(); |
| | | } |
| | | |
| | | protected override void OnPreClose() |
| | | { |
| | | base.OnPreClose(); |
| | | EventBroadcast.Instance.RemoveListener<BattleDmgInfo>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken); |
| | | EventBroadcast.Instance.RemoveListener<string, JsonData>(EventName.BATTLE_END, OnBattleEnd); |
| | | UnregisterEvents(); |
| | | } |
| | | |
| | | protected override void OnOpen() |
| | |
| | | protected override void OnClose() |
| | | { |
| | | base.OnClose(); |
| | | if (battleField != null) |
| | | { |
| | | battleField.OnBattlePause -= OnBattlePause; |
| | | battleField.OnBattleRun -= OnBattleRun; |
| | | battleField.OnSpeedRatioChange -= OnSpeedRatioChange; |
| | | 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 UnregisterEvents() |
| | | { |
| | | EventBroadcast.Instance.RemoveListener<BattleDmgInfo>(EventName.BATTLE_DAMAGE_TAKEN, OnDamageTaken); |
| | | EventBroadcast.Instance.RemoveListener<string, JsonData>(EventName.BATTLE_END, OnBattleEnd); |
| | | } |
| | | |
| | | private void InitializePools() |
| | | { |
| | | damagePrefabPool = GameObjectPoolManager.Instance.RequestPool(UILoader.LoadPrefab("DamageContent")); |
| | | } |
| | | |
| | | public void SetBattleField(BattleField _battleField) |
| | | { |
| | | CleanupBattleField(); |
| | | ClearContent(string.Empty, true); |
| | | |
| | | battleField = _battleField; |
| | | RegisterBattleFieldEvents(); |
| | | } |
| | | |
| | | private void RegisterBattleFieldEvents() |
| | | { |
| | | if (battleField == null) return; |
| | | |
| | | battleField.OnBattlePause += OnBattlePause; |
| | | battleField.OnBattleRun += OnBattleRun; |
| | | battleField.OnSpeedRatioChange += OnSpeedRatioChange; |
| | | } |
| | | |
| | | private void UnregisterBattleFieldEvents() |
| | | { |
| | | if (battleField == null) return; |
| | | |
| | | battleField.OnBattlePause -= OnBattlePause; |
| | | battleField.OnBattleRun -= OnBattleRun; |
| | | battleField.OnSpeedRatioChange -= OnSpeedRatioChange; |
| | | } |
| | | |
| | | 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 SetSelfDamage(BattleDmgInfo damageInfo) |
| | | { |
| | | if (damageInfo.casterDamageList.Count > 0) |
| | | { |
| | | GameObject damageContent = damagePrefabPool.Request(); |
| | | DamageContent content = damageContent.GetComponent<DamageContent>(); |
| | | damageContent.transform.SetParent(damageNode, false); |
| | | |
| | | var heroRect = damageInfo.casterObj.heroRectTrans; |
| | | if (heroRect == null) |
| | | { |
| | | damagePrefabPool.Release(damageContent); |
| | | return; |
| | | } |
| | | |
| | | var contentRect = content.GetComponent<RectTransform>(); |
| | | var contentParentRect = contentRect.parent as RectTransform; |
| | | |
| | | // 获取 heroRect 的世界坐标(锚点为中心) |
| | | Vector3 worldTargetPos = heroRect.transform.TransformPoint(heroRect.rect.center); |
| | | |
| | | // 转换到 content 父节点下的 anchoredPosition |
| | | Vector2 anchoredPos; |
| | | RectTransformUtility.ScreenPointToLocalPointInRectangle( |
| | | contentParentRect, |
| | | RectTransformUtility.WorldToScreenPoint(null, worldTargetPos), |
| | | null, |
| | | out anchoredPos); |
| | | |
| | | // 设置动态位置(会覆盖配置中的位置) |
| | | Vector2 beginPos = anchoredPos; |
| | | Vector2 endPos = anchoredPos + new Vector2(0, 150); |
| | | content.SetPosition(beginPos, endPos); |
| | | |
| | | // 设置速度比例 |
| | | if (battleField != null) |
| | | { |
| | | content.SetRatio(battleField.speedRatio, 1f); |
| | | } |
| | | |
| | | content.SetDamage(damageInfo, damageInfo.casterDamageList, () => RemoveDamageContent(content)); |
| | | damageContentList.Add(content); |
| | | } |
| | | } |
| | | |
| | | private void SetTargetDamage(BattleDmgInfo damageInfo) |
| | | { |
| | | if (damageInfo.targetDamageList.Count > 0) |
| | | { |
| | | GameObject damageContent = damagePrefabPool.Request(); |
| | | DamageContent content = damageContent.GetComponent<DamageContent>(); |
| | | damageContent.transform.SetParent(damageNode, false); |
| | | |
| | | var heroRect = damageInfo.hurtObj.heroRectTrans; |
| | | if (heroRect == null) |
| | | { |
| | | damagePrefabPool.Release(damageContent); |
| | | return; |
| | | } |
| | | |
| | | var contentRect = content.GetComponent<RectTransform>(); |
| | | var contentParentRect = contentRect.parent as RectTransform; |
| | | |
| | | // 获取 heroRect 的世界坐标(锚点为中心) |
| | | Vector3 worldTargetPos = heroRect.transform.TransformPoint(heroRect.rect.center); |
| | | |
| | | // 转换到 content 父节点下的 anchoredPosition |
| | | Vector2 anchoredPos; |
| | | RectTransformUtility.ScreenPointToLocalPointInRectangle( |
| | | contentParentRect, |
| | | RectTransformUtility.WorldToScreenPoint(null, worldTargetPos), |
| | | null, |
| | | out anchoredPos); |
| | | |
| | | // 设置动态位置(会覆盖配置中的位置) |
| | | Vector2 beginPos = anchoredPos; |
| | | Vector2 endPos = anchoredPos + new Vector2(0, 150); |
| | | content.SetPosition(beginPos, endPos); |
| | | |
| | | // 设置速度比例 |
| | | if (battleField != null) |
| | | { |
| | | content.SetRatio(battleField.speedRatio, 1f); |
| | | } |
| | | |
| | | content.SetDamage(damageInfo, damageInfo.targetDamageList, () => RemoveDamageContent(content)); |
| | | damageContentList.Add(content); |
| | | } |
| | | } |
| | | |
| | | public void SetBattleField(BattleField _battleField) |
| | | { |
| | | if (battleField != null) |
| | | { |
| | | battleField.OnBattlePause -= OnBattlePause; |
| | | battleField.OnBattleRun -= OnBattleRun; |
| | | battleField.OnSpeedRatioChange -= OnSpeedRatioChange; |
| | | } |
| | | ClearContent(string.Empty, true); |
| | | battleField = _battleField; |
| | | battleField.OnBattlePause += OnBattlePause; |
| | | battleField.OnBattleRun += OnBattleRun; |
| | | battleField.OnSpeedRatioChange += OnSpeedRatioChange; |
| | | } |
| | | |
| | | private void OnSpeedRatioChange(float newSpeedRatio) |
| | |
| | | { |
| | | if (isPause) |
| | | { |
| | | foreach (var content in damageContentList) |
| | | { |
| | | content.Stop(); |
| | | } |
| | | PauseAllDamageContent(); |
| | | } |
| | | else |
| | | { |
| | | foreach (var content in damageContentList) |
| | | { |
| | | content.Resume(); |
| | | } |
| | | 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, |
| | | RectTransformUtility.WorldToScreenPoint(null, worldTargetPos), |
| | | null, |
| | | out anchoredPos); |
| | | |
| | | return anchoredPos; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 配置DamageContent的速度、伤害数据和回调 |
| | | /// </summary> |
| | | private void SetupDamageContent(DamageContent content, List<BattleDmg> damageList, BattleDmgInfo damageInfo) |
| | | { |
| | | if (battleField != null) |
| | | { |
| | | content.SetRatio(battleField.speedRatio, 1f); |
| | | } |
| | | |
| | | content.SetDamage(damageInfo, damageList, () => RemoveDamageContent(content)); |
| | | damageContentList.Add(content); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 移除DamageContent对象 |
| | | /// </summary> |
| | | private void RemoveDamageContent(DamageContent content) |
| | | { |
| | | damageContentList.Remove(content); |
| | | damagePrefabPool.Release(content.gameObject); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 清除所有伤害显示内容 |
| | | /// </summary> |
| | | private void ClearContent(string guid, bool force = false) |
| | | { |
| | | if ((battleField != null && battleField.guid == guid) || force) |
| | | { |
| | | for (int i = damageContentList.Count - 1; i >= 0; i--) |
| | | { |
| | | var content = damageContentList[i]; |
| | | content.Stop(); |
| | | RemoveDamageContent(content); |
| | | } |
| | | damageContentList.Clear(); |
| | | } |
| | | } |
| | | |
| | | private void PauseAllDamageContent() |
| | | { |
| | | 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) |