| | |
| | | using UnityEngine.UI; |
| | | using DG.Tweening; |
| | | using DG.Tweening.Core; |
| | | |
| | | using System.Linq; |
| | | |
| | | public static class BattleUtility |
| | | { |
| | | // 其他通用的战斗工具方法可以放在这里 |
| | | |
| | | public static TweenerCore<Vector2, Vector2, DG.Tweening.Plugins.Options.VectorOptions> MoveToTarget(RectTransform transform, RectTransform target, Vector2 offset, float duration, Action onComplete = null) |
| | | |
| | | public static void MarkStartAndEnd(RectTransform startNode, RectTransform endNode) |
| | | { |
| | | Vector3 targetWorldPos = target.TransformPoint(target.anchoredPosition + offset); |
| | | // 运行时才执行 |
| | | if (!Application.isPlaying) |
| | | { |
| | | Debug.LogWarning("请在运行时使用该功能!"); |
| | | return; |
| | | } |
| | | |
| | | RectTransform parentRect = transform.parent as RectTransform; |
| | | var battleField = BattleManager.Instance.storyBattleField; |
| | | if (battleField == null) |
| | | { |
| | | Debug.LogError("BattleManager.storyBattleField 未初始化!"); |
| | | return; |
| | | } |
| | | |
| | | Vector2 targetAnchoredPos; |
| | | RectTransformUtility.ScreenPointToLocalPointInRectangle( |
| | | parentRect, |
| | | RectTransformUtility.WorldToScreenPoint(null, targetWorldPos), |
| | | null, |
| | | out targetAnchoredPos); |
| | | |
| | | // 3. DOTween 移动 |
| | | return transform.DOAnchorPos(targetAnchoredPos, duration) |
| | | .SetEase(Ease.Linear) |
| | | .OnComplete(() => onComplete?.Invoke()); |
| | | BattleWin battleWin = UIManager.Instance.GetUI<BattleWin>(); |
| | | |
| | | RectTransform canvasRect = battleWin.transform as RectTransform; |
| | | |
| | | CreateMarker(canvasRect, startNode, "StartMarker"); |
| | | CreateMarker(canvasRect, endNode, "EndMarker"); |
| | | } |
| | | |
| | | private static void CreateMarker(RectTransform canvasRect, RectTransform targetNode, string markerName) |
| | | { |
| | | // 获取目标节点的世界坐标(中心点) |
| | | Vector3 worldPos = targetNode.TransformPoint(targetNode.rect.center); |
| | | |
| | | // 转换到Canvas本地坐标 |
| | | Vector2 localPoint; |
| | | RectTransformUtility.ScreenPointToLocalPointInRectangle( |
| | | canvasRect, |
| | | RectTransformUtility.WorldToScreenPoint(null, worldPos), |
| | | null, |
| | | out localPoint); |
| | | |
| | | // 创建RawImage |
| | | GameObject marker = new GameObject(markerName, typeof(RawImage)); |
| | | GameObject.Destroy(marker, 5f); |
| | | marker.transform.SetParent(canvasRect, false); |
| | | var rawImage = marker.GetComponent<RawImage>(); |
| | | rawImage.color = Color.white; |
| | | rawImage.rectTransform.sizeDelta = new Vector2(100, 100); |
| | | rawImage.rectTransform.anchoredPosition = localPoint; |
| | | } |
| | | |
| | | |
| | | public static TweenerCore<Vector2, Vector2, DG.Tweening.Plugins.Options.VectorOptions> MoveToTarget( |
| | | RectTransform transform, RectTransform target, Vector2 offset, float duration, Action onComplete = null) |
| | | { |
| | | |
| | | // 获取目标节点的世界坐标(中心点) |
| | | Vector3 worldPos = target.TransformPoint(target.rect.center + offset); |
| | | |
| | | RectTransform canvasRect = transform.parent as RectTransform; |
| | | |
| | | // 转换到Canvas本地坐标 |
| | | Vector2 localPoint; |
| | | RectTransformUtility.ScreenPointToLocalPointInRectangle( |
| | | canvasRect, |
| | | RectTransformUtility.WorldToScreenPoint(null, worldPos), |
| | | null, |
| | | out localPoint); |
| | | |
| | | // 创建RawImage |
| | | |
| | | var tween = transform.DOAnchorPos(localPoint, duration).SetEase(Ease.Linear); |
| | | tween.onComplete += () => |
| | | { |
| | | onComplete?.Invoke(); |
| | | }; |
| | | |
| | | // MarkStartAndEnd(transform as RectTransform, target); |
| | | |
| | | |
| | | // // 1. 获取目标的世界坐标(加 offset) |
| | | // Vector3 targetWorldPos = target.TransformPoint(target.anchoredPosition + offset); |
| | | |
| | | // // 2. 获取源节点的 parent |
| | | // RectTransform sourceParent = transform.parent as RectTransform; |
| | | // if (sourceParent == null) |
| | | // { |
| | | // BattleDebug.LogError("源节点没有父节点,无法转换坐标!"); |
| | | // return null; |
| | | // } |
| | | |
| | | // // 3. 把目标世界坐标转换到源 parent 的本地坐标 |
| | | // Vector2 targetAnchoredPos; |
| | | // RectTransformUtility.ScreenPointToLocalPointInRectangle( |
| | | // sourceParent, |
| | | // RectTransformUtility.WorldToScreenPoint(CameraManager.uiCamera, targetWorldPos), |
| | | // CameraManager.uiCamera, |
| | | // out targetAnchoredPos); |
| | | |
| | | // // 4. DOTween 移动 |
| | | // var tween = transform.DOAnchorPos(targetAnchoredPos, duration).SetEase(Ease.Linear); |
| | | // tween.onComplete += () => |
| | | // { |
| | | // onComplete?.Invoke(); |
| | | // }; |
| | | |
| | | return tween; |
| | | } |
| | | |
| | | public static string DisplayDamageNum(long num, int attackType) |
| | | { |
| | | // 服务器位数到客户端类型ID的映射 |
| | | Dictionary<int, int> serverToClientTypeMap = new Dictionary<int, int> |
| | | { |
| | | { 1, 2 }, // 普通伤血 |
| | | { 2, 4 }, // 恢复回血 |
| | | { 3, 8 }, // 反弹伤血 |
| | | { 4, 16 }, // 持续伤血 |
| | | { 5, 32 }, // 格挡 |
| | | { 7, 64 }, // 暴击伤害 |
| | | { 9, 128 }, // 闪避 |
| | | // 其它类型如需补充可继续添加 |
| | | }; |
| | | |
| | | int damageTypeValue = 0; |
| | | for (int i = 0; i < 32; i++) |
| | | { |
| | | int flag = 1 << i; |
| | | if ((attackType & flag) != 0) |
| | | { |
| | | // 只处理有映射的类型 |
| | | if (serverToClientTypeMap.TryGetValue(i + 1, out int clientTypeId)) |
| | | { |
| | | damageTypeValue += clientTypeId; |
| | | } |
| | | } |
| | | } |
| | | DamageType damageType = (DamageType)damageTypeValue; |
| | | |
| | | var config = DamageNumConfig.Get(damageTypeValue); |
| | | var basePowerStr = UIHelper.ReplaceLargeArtNum(num); |
| | | var result = string.Empty; |
| | | for (int i = 0; i < basePowerStr.Length; i++) |
| | | { |
| | | var numChar = (char)GetDamageNumKey(config, basePowerStr[i]); |
| | | if (numChar > 0) |
| | | { |
| | | result += numChar; |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | public static int GetMainTargetPositionNum(BattleObject caster, List<HB427_tagSCUseSkill.tagSCUseSkillHurt> targetList, SkillConfig skillConfig) |
| | | { |
| | | int returnIndex = 0; |
| | | // 根据敌方血量阵营 存活人数来选择 |
| | | BattleCamp battleCamp = skillConfig.TagFriendly != 0 ? caster.Camp : caster.GetEnemyCamp(); |
| | | List<BattleObject> targetObjList = caster.battleField.battleObjMgr.GetBattleObjList(battleCamp); |
| | | |
| | | |
| | | // 瞄准的目标范围,如果目标个数为0则为范围内全部 |
| | | // 0 全部范围 |
| | | // 1 对位,默认只选1个 |
| | | // 2 前排 |
| | | // 3 后排 |
| | | // 4 纵排,按对位规则选择纵排 |
| | | // 5 自己,默认只选自己 |
| | | // 6 继承主技能/来源技能目标 |
| | | // 一般是额外触发的技能使用,如概率附加某buff |
| | | // 额外触发的技能如果目标与主技能不一致,则重新设定目标即可 |
| | | // 或被动触发的技能,可继承触发来源技能的攻防双方关系 |
| | | |
| | | switch (skillConfig.TagAim) |
| | | { |
| | | case 0: |
| | | // 全部范围 |
| | | //全部范围+敌我+目标数量为6 |
| | | //就是取敌我站位中的2号位 |
| | | returnIndex = 1; |
| | | break; |
| | | case 1: |
| | | returnIndex = caster.teamHero.positionNum; |
| | | // 寻找对位是否有人 没有的话选择最小的 |
| | | List<BattleObject> opposite = new List<BattleObject>(from bo in targetObjList where !bo.IsDead() && bo.teamHero.positionNum == returnIndex select bo); |
| | | if (opposite.Count > 0) |
| | | { |
| | | returnIndex = opposite[0].teamHero.positionNum; |
| | | } |
| | | else |
| | | { |
| | | opposite = new List<BattleObject>(from bo in targetObjList where !bo.IsDead() select bo); |
| | | opposite.Sort((a, b) => a.teamHero.positionNum.CompareTo(b.teamHero.positionNum)); |
| | | returnIndex = opposite.Count > 0 ? opposite[0].teamHero.positionNum : returnIndex; |
| | | } |
| | | break; |
| | | case 2: |
| | | // 看看对面前排是否都活着 |
| | | List<BattleObject> front = new List<BattleObject>(from bo in targetObjList where !bo.IsDead() && bo.teamHero.positionNum < 3 select bo); |
| | | if (front.Count > 0) |
| | | { |
| | | returnIndex = 1; |
| | | } |
| | | else |
| | | { |
| | | returnIndex = 4; |
| | | } |
| | | break; |
| | | case 3: |
| | | // 看看对面后排是否都活着 |
| | | List<BattleObject> back = new List<BattleObject>(from bo in targetObjList where !bo.IsDead() && bo.teamHero.positionNum >= 3 select bo); |
| | | if (back.Count > 0) |
| | | { |
| | | returnIndex = 4; |
| | | } |
| | | else |
| | | { |
| | | returnIndex = 1; |
| | | } |
| | | break; |
| | | // 4 纵排,按对位规则选择纵排 |
| | | case 4: |
| | | List<BattleObject> vertical = new List<BattleObject>(from bo in targetObjList where !bo.IsDead() && (bo.teamHero.positionNum - caster.teamHero.positionNum) % 3 == 0 select bo); |
| | | // TODO YYL |
| | | break; |
| | | // 5 自己,默认只选自己 |
| | | case 5: |
| | | returnIndex = caster.teamHero.positionNum; |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | |
| | | return returnIndex; |
| | | } |
| | | |
| | | public static int GetDamageNumKey(DamageNumConfig config, int _num) |
| | | { |
| | | if (_num == 46) return config.nums[10]; // '.' |
| | | else if (_num == 107) return config.nums[11]; // 'k' |
| | | else if (_num == 109) return config.nums[12]; // 'm' |
| | | else if (_num == 98) return config.nums[13]; // 'b' |
| | | else if (_num == 116) return config.nums[14]; // 't' |
| | | return config.nums[_num - 48]; |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 保证所有分配项加起来等于totalDamage,避免因整除导致的误差 |
| | | /// </summary> |
| | | public static List<long> DivideDamageToList(int[] damageDivide, long totalDamage) |
| | | { |
| | | List<long> fixedDamageList = new List<long>(); |
| | | long assigned = 0; |
| | | int count = damageDivide.Length; |
| | | |
| | | for (int i = 0; i < count; i++) |
| | | { |
| | | long damage; |
| | | if (i == count - 1) |
| | | { |
| | | // 最后一个分配项修正为剩余 |
| | | damage = totalDamage - assigned; |
| | | } |
| | | else |
| | | { |
| | | damage = (totalDamage * damageDivide[i] + 5000) / 10000; // 四舍五入 |
| | | assigned += damage; |
| | | } |
| | | fixedDamageList.Add(damage); |
| | | } |
| | | return fixedDamageList; |
| | | } |
| | | |
| | | public static List<HB422_tagMCTurnFightObjDead> FindDeadPack(List<GameNetPackBasic> packList) |
| | | { |
| | | List<HB422_tagMCTurnFightObjDead> deadPacks = new List<HB422_tagMCTurnFightObjDead>(); |
| | | for (int i = 0; i < packList.Count; i++) |
| | | { |
| | | var pack = packList[i]; |
| | | // 寻找死亡包 找到死亡包之后要找掉落包 不能超过技能包 |
| | | if (pack is HB422_tagMCTurnFightObjDead) |
| | | { |
| | | var deadPack = pack as HB422_tagMCTurnFightObjDead; |
| | | deadPacks.Add(deadPack); |
| | | } |
| | | else if (pack is CustomHB426CombinePack) |
| | | { |
| | | // 找死亡包不要越过技能包 |
| | | var combinePack = pack as CustomHB426CombinePack; |
| | | if (combinePack.startTag.Tag.StartsWith("Skill_")) |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | return deadPacks; |
| | | } |
| | | |
| | | |
| | | public static List<HB423_tagMCTurnFightObjReborn> FindRebornPack(List<GameNetPackBasic> packList) |
| | | { |
| | | List<HB423_tagMCTurnFightObjReborn> rebornPack = new List<HB423_tagMCTurnFightObjReborn>(); |
| | | for (int i = 0; i < packList.Count; i++) |
| | | { |
| | | var pack = packList[i]; |
| | | // 寻找死亡包 找到死亡包之后要找掉落包 不能超过技能包 |
| | | if (pack is HB423_tagMCTurnFightObjReborn) |
| | | { |
| | | var deadPack = pack as HB423_tagMCTurnFightObjReborn; |
| | | rebornPack.Add(deadPack); |
| | | } |
| | | else if (pack is CustomHB426CombinePack) |
| | | { |
| | | // 找死亡包不要越过技能包 |
| | | var combinePack = pack as CustomHB426CombinePack; |
| | | if (combinePack.startTag.Tag.StartsWith("Skill_")) |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | return rebornPack; |
| | | } |
| | | } |