| | |
| | | |
| | | public partial class SkillConfig : ConfigBase<int, SkillConfig> |
| | | { |
| | | //增益: 3 5 |
| | | // 减益: 4 6 14 |
| | | |
| | | public static readonly int[] GainSkillType = new int[] { 3, 5 }; // 1-普通攻击 2-被动技能 3-专属技能 |
| | | |
| | | public static readonly int[] DebuffSkillType = new int[] { 4, 6, 14 }; |
| | | |
| | | public SkillType skillType; |
| | | public SkillCastMode castMode; |
| | | |
| | |
| | | tempDic[SkillLV] = this; |
| | | } |
| | | |
| | | public bool IsGainBuff() |
| | | { |
| | | return Array.Exists(GainSkillType, type => type == (int)skillType); |
| | | } |
| | | |
| | | public bool IsDebuff() |
| | | { |
| | | return Array.Exists(DebuffSkillType, type => type == (int)skillType); |
| | | } |
| | | |
| | | public MotionName GetMotionName() |
| | | { |
| | | return Enum.Parse<MotionName>(SkillMotionName); |
| | |
| | | { |
| | | battleField.PlayRecord(skillAction); |
| | | } |
| | | else |
| | | { |
| | | battleField.DistributeNextPackage(); |
| | | } |
| | | |
| | | } |
| | | |
| | |
| | | public class BattleField |
| | | { |
| | | public Action<int, int> OnRoundChange; |
| | | public Action<bool> OnBattlePause; |
| | | |
| | | public Action<float> OnSpeedRatioChange; // 添加战斗速度变化的回调 |
| | | |
| | | public Action OnBattleRun; // 添加战斗运行时的回调 |
| | | |
| | | public BattleObjMgr battleObjMgr; |
| | | |
| | | public BattleEffectMgr battleEffectMgr; |
| | | |
| | | public BattleTweenMgr battleTweenMgr; |
| | | |
| | | public RecordPlayer recordPlayer; |
| | | |
| | | public IOperationAgent operationAgent; |
| | | |
| | | public byte turnMax; |
| | | |
| | | public int round = 0; |
| | | |
| | | public string guid = string.Empty;//等于string.Empty的时候代表是StoryBattleField 是主线副本 |
| | | |
| | | public string guid = string.Empty; |
| | | public int MapID = 0; |
| | | |
| | | public int FuncLineID = 0; |
| | | |
| | | public float speedRatio = 1.1f; |
| | | |
| | | public JsonData extendData; |
| | | |
| | | public bool IsBattleFinish |
| | | { |
| | | get; |
| | | protected set; |
| | | } |
| | | |
| | | public bool IsBattleFinish { get; protected set; } |
| | | public bool rejectNewPackage = false; |
| | | |
| | | private bool m_IsPause = false; |
| | | |
| | | public bool IsPause |
| | | { |
| | | get |
| | | { |
| | | return m_IsPause; |
| | | } |
| | | get { return m_IsPause; } |
| | | set |
| | | { |
| | | |
| | | if (value) |
| | | { |
| | | m_IsPause = value; |
| | |
| | | } |
| | | |
| | | public BattleRootNode battleRootNode; |
| | | |
| | | private BattleMode battleMode; |
| | | public event Action<BattleMode> ChangeBattleModeEvent; |
| | | |
| | | public Action<bool> OnBattlePause; |
| | | |
| | | protected List<TeamBase> redTeamList = null; |
| | | |
| | | protected List<TeamBase> blueTeamList = null; |
| | | |
| | | protected int redTeamIndex = 0; |
| | | |
| | | protected int blueTeamIndex = 0; |
| | | |
| | | public BattleField(string _guid) |
| | |
| | | |
| | | public void SetSpeedRatio(float ratio) |
| | | { |
| | | bool isChange = speedRatio != ratio; |
| | | speedRatio = ratio; |
| | | battleObjMgr.SetSpeedRatio(ratio); |
| | | recordPlayer.SetSpeedRatio(ratio); |
| | | battleEffectMgr.SetSpeedRatio(ratio); |
| | | battleTweenMgr.SetSpeedRatio(ratio); |
| | | |
| | | if (isChange) |
| | | { |
| | | OnSpeedRatioChange?.Invoke(ratio); |
| | | } |
| | | } |
| | | |
| | | protected virtual void SetBattleStartState() |
| | |
| | | } |
| | | if (recordPlayer == null || battleObjMgr == null) |
| | | return; |
| | | |
| | | recordPlayer.Run(); |
| | | battleObjMgr.Run(); |
| | | battleEffectMgr.Run(); |
| | |
| | | } |
| | | |
| | | operationAgent.Run(); |
| | | |
| | | // 触发 UI 层的更新回调 |
| | | OnBattleRun?.Invoke(); |
| | | } |
| | | |
| | | |
| | |
| | | if (null != skillConfig && obj != null) |
| | | { |
| | | // 飘字 |
| | | obj.heroInfoBar.ShowTips(skillConfig.SkillName); |
| | | BattleHeroInfoBar.TipsInfo tipsInfo = new BattleHeroInfoBar.TipsInfo(); |
| | | tipsInfo.message = skillConfig.SkillName; |
| | | tipsInfo.useArtText = false; |
| | | tipsInfo.followCharacter = true; |
| | | tipsInfo.scaleRatio = 1f; |
| | | tipsInfo.textColor = skillConfig.IsDebuff() ? |
| | | Color.red : skillConfig.IsGainBuff() ? Color.green : Color.white; |
| | | tipsInfo.showBackground = true; |
| | | |
| | | obj.heroInfoBar.ShowTips(tipsInfo); |
| | | } |
| | | } |
| | | |
| | |
| | | using System; |
| | | using LitJson; |
| | | |
| | | |
| | | // 这个界面是 persistent的界面 |
| | | public class BattleHUDWin : UIBase |
| | | { |
| | | // 组件引用 |
| | | // private List<HUDContent> damageList = new List<HUDContent>(); |
| | | |
| | | // private List<BuffContent> buffList = new List<BuffContent>(); |
| | | |
| | | 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() |
| | |
| | | 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")); |
| | | // buffIconPrefabPool = GameObjectPoolManager.Instance.RequestPool(); |
| | | // buffLabelPrefabPool = GameObjectPoolManager.Instance.RequestPool(ResManager.Instance.LoadAsset<GameObject>("UIComp", "BuffContent")); |
| | | } |
| | | |
| | | private void OnBattleEnd(string guid, JsonData data) |
| | |
| | | protected override void OnClose() |
| | | { |
| | | base.OnClose(); |
| | | battleField.OnBattlePause -= OnBattlePause; |
| | | battleField = null; |
| | | if (battleField != null) |
| | | { |
| | | battleField.OnBattlePause -= OnBattlePause; |
| | | battleField.OnBattleRun -= OnBattleRun; |
| | | battleField.OnSpeedRatioChange -= OnSpeedRatioChange; |
| | | battleField = null; |
| | | } |
| | | } |
| | | |
| | | protected override void NextFrameAfterOpen() |
| | |
| | | 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(damageInfo, () => RemoveDamageContent(content)); |
| | | damageContentList.Add(content); |
| | | |
| | | |
| | | var heroRect = damageInfo.hurtObj.heroRectTrans; |
| | | if (heroRect == null) |
| | | { |
| | | damagePrefabPool.Release(damageContent); |
| | | return; |
| | | } |
| | | |
| | | var contentRect = content.GetComponent<RectTransform>(); |
| | | var contentParentRect = contentRect.parent as RectTransform; |
| | |
| | | null, |
| | | out anchoredPos); |
| | | |
| | | contentRect.anchoredPosition = anchoredPos; |
| | | // 设置初始位置和结束位置 |
| | | content.beginPos = anchoredPos; |
| | | content.endPos = anchoredPos + new Vector2(0, 150); |
| | | |
| | | // 设置速度比例 |
| | | if (battleField != null) |
| | | { |
| | | content.SetRatio(battleField.speedRatio, 1f); |
| | | } |
| | | |
| | | // 设置伤害数据并开始播放 |
| | | content.SetDamage(damageInfo, () => 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) |
| | | { |
| | | foreach (var content in damageContentList) |
| | | { |
| | | content.SetRatio(newSpeedRatio, 1f); |
| | | } |
| | | } |
| | | |
| | | private void OnBattlePause(bool isPause) |
| | | { |
| | | // 游戏暂停 |
| | | if (isPause) |
| | | { |
| | | foreach (var content in damageContentList) |
| | |
| | | content.Stop(); |
| | | } |
| | | } |
| | | // 游戏恢复 |
| | | else |
| | | { |
| | | foreach (var content in damageContentList) |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | private void OnBattleRun() |
| | | { |
| | | for (int i = damageContentList.Count - 1; i >= 0; i--) |
| | | { |
| | | if (i < damageContentList.Count) |
| | | { |
| | | damageContentList[i].Run(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | public void SetSpeedRatio(float ratio) |
| | | { |
| | | motionBase.SetSpeedRatio(ratio); |
| | | heroInfoBar.SetSpeedRatio(ratio); |
| | | } |
| | | |
| | | |
| | |
| | | |
| | | private static float m_modelScaleRate = 0f; |
| | | |
| | | private static float modelScaleRate |
| | | public static float modelScaleRate |
| | | { |
| | | get |
| | | { |
| | |
| | | // 删除buff |
| | | public void RemoveBuff(HB429_tagSCBuffDel vNetData) |
| | | { |
| | | HB428_tagSCBuffRefresh buffData = null; |
| | | |
| | | bool isRemove = false; |
| | | |
| | | if (buffDataDict.TryGetValue(vNetData.BuffID, out buffData)) |
| | | { |
| | | isRemove = true; |
| | | buffDataDict.Remove(vNetData.BuffID); |
| | | } |
| | | |
| | | if (!isRemove) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | var tempvNetData = vNetData; |
| | | BuffUnmountAction buffRemoveAction = new BuffUnmountAction(battleObject.battleField, new List<HB429_tagSCBuffDel>() { vNetData }, () => |
| | | { |
| | | HB428_tagSCBuffRefresh buffData = null; |
| | | |
| | | bool isRemove = false; |
| | | |
| | | if (buffDataDict.TryGetValue(tempvNetData.BuffID, out buffData)) |
| | | { |
| | | isRemove = true; |
| | | buffDataDict.Remove(tempvNetData.BuffID); |
| | | } |
| | | |
| | | if (!isRemove) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | bool isRemoveEffect = false; |
| | | |
| | | int remainCnt = -1; |
| | |
| | | |
| | | if (buffGroupStateDict[BattleConst.HardControlGroup.ToString()].Contains(skillConfig.BuffState)) |
| | | { |
| | | BattleDebug.LogError("[BattleObjectBuffMgr]移除对象 " + battleObject.ObjID + " 的buff id " + vNetData.BuffID + " BuffState is " + skillConfig.BuffState + " 是否删除了字典内的内容 " + isRemove.ToString() + " 是否删除了特效 " + isRemoveEffect.ToString() + " pack uid 是 " + vNetData.packUID); |
| | | BattleDebug.LogError("[BattleObjectBuffMgr]移除对象 " + battleObject.ObjID + " 的buff id " + tempvNetData.BuffID + " BuffState is " + skillConfig.BuffState + " 是否删除了字典内的内容 " + isRemove.ToString() + " 是否删除了特效 " + isRemoveEffect.ToString() + " pack uid 是 " + vNetData.packUID); |
| | | } |
| | | } |
| | | |
| | |
| | | return; |
| | | } |
| | | |
| | | // bool isNew = false; |
| | | if (buffDataDict.ContainsKey(vNetData.BuffID)) |
| | | { |
| | | buffDataDict[vNetData.BuffID] = vNetData; |
| | | } |
| | | else |
| | | { |
| | | // isNew = true; |
| | | buffDataDict.Add(vNetData.BuffID, vNetData); |
| | | } |
| | | var tempvNetData = vNetData; |
| | | |
| | | if (vNetData.IsAdd != 0) |
| | | if (tempvNetData.IsAdd != 0) |
| | | { |
| | | BuffMountAction buffMountAction = new BuffMountAction(battleObject.battleField, new List<HB428_tagSCBuffRefresh>() { vNetData }, () => |
| | | BuffMountAction buffMountAction = new BuffMountAction(battleObject.battleField, new List<HB428_tagSCBuffRefresh>() { tempvNetData }, () => |
| | | { |
| | | if (buffDataDict.ContainsKey(tempvNetData.BuffID)) |
| | | { |
| | | buffDataDict[tempvNetData.BuffID] = tempvNetData; |
| | | } |
| | | else |
| | | { |
| | | buffDataDict.Add(tempvNetData.BuffID, tempvNetData); |
| | | } |
| | | |
| | | if (battleObject.IsDead()) |
| | | { |
| | | return; |
| | |
| | | // 已经存在相同的buff特效 |
| | | if (buffEffectDict.TryGetValue(skillConfig.BuffEffect, out KeyValuePair<BattleEffectPlayer, HashSet<uint>> pair)) |
| | | { |
| | | pair.Value.Add(vNetData.BuffID); |
| | | pair.Value.Add(tempvNetData.BuffID); |
| | | } |
| | | else |
| | | { |
| | |
| | | effect.BindBone(battleObject.motionBase.skeletonAnim, effect.effectConfig.nodeName); |
| | | |
| | | HashSet<uint> buffIdSet = new HashSet<uint>(); |
| | | buffIdSet.Add(vNetData.BuffID); |
| | | buffIdSet.Add(tempvNetData.BuffID); |
| | | buffEffectDict.Add(skillConfig.BuffEffect, new KeyValuePair<BattleEffectPlayer, HashSet<uint>>(effect, buffIdSet)); |
| | | } |
| | | |
| | |
| | | |
| | | if (skillConfig != null && buffGroupStateDict[BattleConst.HardControlGroup.ToString()].Contains(skillConfig.BuffState)) |
| | | { |
| | | BattleDebug.LogError("[BattleObjectBuffMgr]添加对象 " + battleObject.ObjID + " 的buff id " + vNetData.BuffID + " pack uid 是 " + vNetData.packUID + " BuffState is " + skillConfig.BuffState); |
| | | BattleDebug.LogError("[BattleObjectBuffMgr]添加对象 " + battleObject.ObjID + " 的buff id " + tempvNetData.BuffID + " pack uid 是 " + tempvNetData.packUID + " BuffState is " + skillConfig.BuffState); |
| | | } |
| | | |
| | | OnBuffChanged(); |
| | |
| | | } |
| | | else |
| | | { |
| | | if (buffDataDict.ContainsKey(tempvNetData.BuffID)) |
| | | { |
| | | buffDataDict[tempvNetData.BuffID] = tempvNetData; |
| | | } |
| | | else |
| | | { |
| | | buffDataDict.Add(tempvNetData.BuffID, tempvNetData); |
| | | } |
| | | // 已经存在的buff 刷新 |
| | | OnBuffChanged(); |
| | | } |
| | |
| | | |
| | | public class MotionBase |
| | | { |
| | | public static float MotionTimeScale = 1f; |
| | | public float MotionTimeScale = 1f; |
| | | public static List<string> AttackMotionList = new List<string> |
| | | { |
| | | MotionName.attack.ToString().ToLower(), |
| | |
| | | |
| | | if (hintConfig != null) |
| | | { |
| | | caster.heroInfoBar.ShowTips(((char)hintConfig.prefix).ToString(), true); |
| | | caster.heroInfoBar.ShowTips(((char)hintConfig.prefix).ToString(), true, false, 1.25f); |
| | | // Debug.Break(); |
| | | } |
| | | } |
| New file |
| | |
| | | using UnityEngine; |
| | | using System; |
| | | |
| | | /// <summary> |
| | | /// 战斗飘字UI控制器:处理缩放、透明度、位置动画逻辑 |
| | | /// </summary> |
| | | [SerializeField] |
| | | public class BattleFloatingUIController |
| | | { |
| | | // Position Settings |
| | | public Vector2 beginPos = Vector2.zero; |
| | | public Vector2 endPos = new Vector2(0, 150); |
| | | |
| | | // Time Settings |
| | | public float scaleChangeTime = 1f / BattleConst.skillMotionFps * 8f + 0.1f; // 7~8帧 (8/30=0.2667秒) |
| | | public float totalShowTime = 1f / BattleConst.skillMotionFps * 24f + 0.1f; // 总时间约24帧 (8+16=24帧) |
| | | |
| | | // Normal Settings |
| | | public Vector3 normalBeginScale = new Vector3(2f, 2f, 2f); |
| | | public Vector3 normalEndScale = new Vector3(1f, 1f, 1f); |
| | | |
| | | // Critical Settings |
| | | public Vector3 critBeginScale = new Vector3(3f, 3f, 3f); |
| | | public Vector3 critEndScale = new Vector3(1.5f, 1.5f, 1.5f); |
| | | |
| | | // Color Settings |
| | | public Color beginColor = new Color(1f, 1f, 1f, 0.5f); |
| | | public Color endColor = new Color(1f, 1f, 1f, 1f); |
| | | |
| | | private RectTransform rectTransform; |
| | | private float timer = 0f; |
| | | private float speedRatio = 1f; |
| | | private float scaleRatio = 1f; |
| | | private bool isCritical = false; |
| | | private Action onFinishCallback; |
| | | private Action<Color> applyColorCallback; |
| | | private GameObject gameObject; |
| | | |
| | | // 添加只读属性以对外暴露 |
| | | public float Timer => timer; |
| | | public float SpeedRatio => speedRatio; |
| | | public float ScaleRatio => scaleRatio; |
| | | |
| | | public BattleFloatingUIController(RectTransform rect, GameObject go, Action<Color> applyColor) |
| | | { |
| | | rectTransform = rect; |
| | | gameObject = go; |
| | | applyColorCallback = applyColor; |
| | | } |
| | | |
| | | public void SetRatio(float speed, float scale) |
| | | { |
| | | speedRatio = speed; |
| | | scaleRatio = scale; |
| | | } |
| | | |
| | | public void Play(bool isCrit, Action onComplete = null) |
| | | { |
| | | isCritical = isCrit; |
| | | onFinishCallback = onComplete; |
| | | timer = 0f; |
| | | |
| | | Vector3 beginScale = isCritical ? critBeginScale : normalBeginScale; |
| | | rectTransform.anchoredPosition = beginPos; |
| | | rectTransform.localScale = beginScale * scaleRatio; |
| | | |
| | | gameObject.SetActive(true); |
| | | } |
| | | |
| | | public void Run() |
| | | { |
| | | if (!gameObject.activeSelf) |
| | | return; |
| | | |
| | | if (timer >= totalShowTime) |
| | | { |
| | | gameObject.SetActive(false); |
| | | onFinishCallback?.Invoke(); |
| | | onFinishCallback = null; |
| | | return; |
| | | } |
| | | |
| | | // 整个过程都往上飘 |
| | | float moveProgress = timer / totalShowTime; |
| | | rectTransform.anchoredPosition = Vector2.Lerp(beginPos, endPos, moveProgress); |
| | | |
| | | Vector3 currentBeginScale = isCritical ? critBeginScale : normalBeginScale; |
| | | Vector3 currentEndScale = isCritical ? critEndScale : normalEndScale; |
| | | |
| | | // 阶段1: 7~8帧内缩放和透明度变化 |
| | | if (timer < scaleChangeTime) |
| | | { |
| | | float scaleProgress = timer / scaleChangeTime; |
| | | rectTransform.localScale = Vector3.Lerp(currentBeginScale, currentEndScale, scaleProgress) * scaleRatio; |
| | | |
| | | Color currentColor = Color.Lerp(beginColor, endColor, scaleProgress); |
| | | applyColorCallback?.Invoke(currentColor); |
| | | } |
| | | // 阶段2: 保持缩放和透明度,继续往上飘 |
| | | else |
| | | { |
| | | rectTransform.localScale = currentEndScale * scaleRatio; |
| | | applyColorCallback?.Invoke(endColor); |
| | | } |
| | | |
| | | timer += 1f / BattleConst.skillMotionFps * speedRatio; |
| | | } |
| | | |
| | | public void Stop() |
| | | { |
| | | // 可以添加暂停逻辑 |
| | | } |
| | | |
| | | public void Resume() |
| | | { |
| | | // 可以添加恢复逻辑 |
| | | } |
| | | } |
| New file |
| | |
| | | fileFormatVersion: 2 |
| | | guid: 60d705fe96fb5584683592ecfef1ba81 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
| | | defaultReferences: [] |
| | | executionOrder: 0 |
| | | icon: {instanceID: 0} |
| | | userData: |
| | | assetBundleName: |
| | | assetBundleVariant: |
| | |
| | | public string message; |
| | | public bool useArtText; |
| | | public bool followCharacter; |
| | | public float scaleRatio; |
| | | |
| | | public Color textColor = Color.white; |
| | | |
| | | public bool showBackground = false; |
| | | } |
| | | |
| | | protected BattleObject battleObject; |
| | |
| | | } |
| | | tipsList.Clear(); |
| | | } |
| | | public void ShowTips(string message, bool useArtText = false, bool followCharacter = false) |
| | | public void ShowTips(string message, bool useArtText = false, bool followCharacter = true, float scaleRatio = 1f) |
| | | { |
| | | messages.Add(new TipsInfo |
| | | { |
| | | message = message, |
| | | useArtText = useArtText, |
| | | followCharacter = followCharacter |
| | | followCharacter = followCharacter, |
| | | scaleRatio = scaleRatio |
| | | }); |
| | | } |
| | | |
| | | public void ShowTips(TipsInfo tipsInfo) |
| | | { |
| | | messages.Add(tipsInfo); |
| | | } |
| | | |
| | | public void SetActive(bool active) |
| | |
| | | gameObject.SetActive(active); |
| | | } |
| | | |
| | | public void PopUpTipsDirectly(string message, bool useArtText = false, bool followCharacter = false) |
| | | public void PopUpTipsDirectly(TipsInfo tipsInfo) |
| | | { |
| | | GameObject prefab = textTips.gameObject; |
| | | |
| | | GameObject go = GameObject.Instantiate(prefab, followCharacter ? transform : battleObject.battleField.battleRootNode.transform); |
| | | GameObject go = GameObject.Instantiate(prefab, tipsInfo.followCharacter ? transform : battleObject.battleField.battleRootNode.transform); |
| | | |
| | | BattleTips tips = go.GetComponent<BattleTips>(); |
| | | |
| | | if (!followCharacter) |
| | | if (!tipsInfo.followCharacter) |
| | | { |
| | | go.transform.position = prefab.transform.position; |
| | | tips.beginPos = go.transform.localPosition; |
| | | tips.endPos = tips.endPos + new Vector2(go.transform.localPosition.x, go.transform.localPosition.y); |
| | | var contentRect = go.GetComponent<RectTransform>(); |
| | | var contentParentRect = contentRect.parent as RectTransform; |
| | | var infoBarRect = GetComponent<RectTransform>(); |
| | | |
| | | Vector3 worldTargetPos = infoBarRect.transform.TransformPoint(infoBarRect.rect.center); |
| | | |
| | | Vector2 anchoredPos; |
| | | RectTransformUtility.ScreenPointToLocalPointInRectangle( |
| | | contentParentRect, |
| | | RectTransformUtility.WorldToScreenPoint(null, worldTargetPos), |
| | | null, |
| | | out anchoredPos); |
| | | |
| | | tips.UpdatePositions(anchoredPos, anchoredPos + new Vector2(0, 150)); |
| | | |
| | | // 同时更新缩放 |
| | | Vector3 newBeginScale = tips.normalBeginScale * tipsInfo.scaleRatio; |
| | | Vector3 newEndScale = tips.normalEndScale * tipsInfo.scaleRatio; |
| | | tips.UpdateScales(newBeginScale, newEndScale); |
| | | } |
| | | |
| | | tips.SetSpeedRatio(battleObject.battleField.speedRatio); |
| | | tips.SetRatio(battleObject.battleField.speedRatio, 1f); |
| | | |
| | | tips.SetText(message, useArtText); |
| | | tips.SetText(tipsInfo.message, tipsInfo.useArtText, false, tipsInfo.textColor); |
| | | |
| | | tips.ShowBackground(tipsInfo.showBackground); |
| | | |
| | | tips.OnFinish = () => |
| | | { |
| | | // TODO YYL 考虑池化 |
| | | tipsList.Remove(tips); |
| | | GameObject.DestroyImmediate(tips.gameObject); |
| | | }; |
| | |
| | | if (messages.Count > 0 && timer >= PopUpInterval) |
| | | { |
| | | // 播放飘字 |
| | | TipsInfo message = messages[0]; |
| | | TipsInfo tipsInfo = messages[0]; |
| | | messages.RemoveAt(0); |
| | | |
| | | PopUpTipsDirectly(message.message, message.useArtText, message.followCharacter); |
| | | PopUpTipsDirectly(tipsInfo); |
| | | |
| | | timer = 0f; |
| | | } |
| | | } |
| | | |
| | | public void SetSpeedRatio(float ratio) |
| | | { |
| | | for (int i = 0; i < tipsList.Count; i++) |
| | | { |
| | | tipsList[i].SetRatio(ratio, 1f); |
| | | } |
| | | } |
| | | } |
| | |
| | | using System; |
| | | using UnityEngine.UI; |
| | | |
| | | public class BattleTips : MonoBehaviour |
| | | public class BattleTips : MonoBehaviour, IBattleFloatingUI |
| | | { |
| | | public Vector2 beginPos = Vector2.zero; |
| | | public Vector2 endPos = new Vector2(0, 150); |
| | | |
| | | public float scaleChangeTime = 0.2667f; // 7~8帧 (8/30=0.2667秒) |
| | | public float totalShowTime = 0.8f; // 总时间约24帧 (8+16=24帧) |
| | | public float timer = 0f; |
| | | |
| | | public Vector3 beginScale = new Vector3(4f, 4f, 4f); |
| | | public Vector3 endScale = new Vector3(2f, 2f, 2f); |
| | | public Color beginColor = new Color(1f, 1f, 1f, 0.5f); |
| | | public Color endColor = new Color(1f, 1f, 1f, 1f); |
| | | |
| | | public RectTransform rectTransform; |
| | | |
| | | public Text tipText; |
| | | |
| | | public Text artText; |
| | | |
| | | public Action OnFinish; |
| | | public Image background; |
| | | |
| | | private float speedRatio = 1f; |
| | | public Vector3 normalBeginScale = new Vector3(2f, 2f, 2f); |
| | | public Vector3 normalEndScale = new Vector3(1f, 1f, 1f); |
| | | |
| | | public void SetSpeedRatio(float ratio) |
| | | public Action OnFinish; // 保留 OnFinish |
| | | |
| | | [SerializeField] |
| | | private BattleFloatingUIController controller; |
| | | |
| | | void Awake() |
| | | { |
| | | speedRatio = ratio; |
| | | InitController(); |
| | | } |
| | | |
| | | public void SetText(string text, bool useArtText = false) |
| | | private void InitController() |
| | | { |
| | | // 初始放大200% 透明度50% 7~8帧内缩回100% 透明度到100% 再往上飘14~16帧 然后消失 (30帧/秒) |
| | | if (controller != null) return; |
| | | |
| | | // 8+16/30=0.8秒 |
| | | |
| | | controller = new BattleFloatingUIController(rectTransform, gameObject, ApplyColor); |
| | | controller.beginPos = beginPos; |
| | | controller.endPos = endPos; |
| | | controller.normalBeginScale = normalBeginScale; |
| | | controller.normalEndScale = normalEndScale; |
| | | } |
| | | |
| | | rectTransform.anchoredPosition = beginPos; |
| | | rectTransform.localScale = beginScale; |
| | | public void SetRatio(float speed, float scale) |
| | | { |
| | | InitController(); // 确保 controller 已初始化 |
| | | controller.SetRatio(speed, scale); |
| | | } |
| | | |
| | | timer = 0f; |
| | | gameObject.SetActive(true); |
| | | public void SetText(string text, bool useArtText = false, bool isCrit = false, Color textColor = default) |
| | | { |
| | | if (textColor == default) |
| | | { |
| | | textColor = Color.white; |
| | | } |
| | | |
| | | InitController(); |
| | | if (useArtText) |
| | | { |
| | | artText.text = text; |
| | | artText.color = beginColor; |
| | | tipText.gameObject.SetActive(false); |
| | | artText.gameObject.SetActive(true); |
| | | } |
| | | else |
| | | { |
| | | tipText.text = text; |
| | | tipText.color = beginColor; |
| | | artText.gameObject.SetActive(false); |
| | | tipText.gameObject.SetActive(true); |
| | | } |
| | | |
| | | controller.beginColor = new Color(textColor.r, textColor.g, textColor.b, controller.beginColor.a); |
| | | controller.endColor = new Color(textColor.r, textColor.g, textColor.b, controller.endColor.a); |
| | | ApplyColor(controller.beginColor); |
| | | Play(isCrit); |
| | | } |
| | | |
| | | |
| | | // 不要使用update |
| | | public void Run() |
| | | public void Play(bool isCrit, Action onComplete = null) |
| | | { |
| | | if (!gameObject.activeSelf) |
| | | return; |
| | | |
| | | if (timer >= totalShowTime) |
| | | InitController(); // 确保 controller 已初始化 |
| | | |
| | | // 合并 OnFinish 和 onComplete |
| | | Action combinedCallback = () => |
| | | { |
| | | gameObject.SetActive(false); |
| | | OnFinish?.Invoke(); |
| | | OnFinish = null; |
| | | return; |
| | | } |
| | | onComplete?.Invoke(); |
| | | }; |
| | | |
| | | controller.Play(isCrit, combinedCallback); |
| | | } |
| | | |
| | | // 整个过程都往上飘 |
| | | float moveProgress = timer / totalShowTime; |
| | | rectTransform.anchoredPosition = Vector2.Lerp(beginPos, endPos, moveProgress); |
| | | public void Run() |
| | | { |
| | | if (controller == null) return; // 防止在 Awake 前调用 |
| | | controller.Run(); |
| | | } |
| | | |
| | | // 阶段1: 7~8帧内缩放从beginScale到endScale,透明度从50%到100% |
| | | if (timer < scaleChangeTime) |
| | | { |
| | | float scaleProgress = timer / scaleChangeTime; |
| | | rectTransform.localScale = Vector3.Lerp(beginScale, endScale, scaleProgress); |
| | | public void Stop() |
| | | { |
| | | if (controller == null) return; |
| | | controller.Stop(); |
| | | } |
| | | |
| | | Color currentColor = Color.Lerp(beginColor, endColor, scaleProgress); |
| | | if (tipText.gameObject.activeSelf) |
| | | tipText.color = currentColor; |
| | | if (artText.gameObject.activeSelf) |
| | | artText.color = currentColor; |
| | | } |
| | | // 阶段2: 缩放完成后,保持endScale和100%透明度,继续往上飘 |
| | | else |
| | | { |
| | | rectTransform.localScale = endScale; |
| | | |
| | | if (tipText.gameObject.activeSelf) |
| | | tipText.color = endColor; |
| | | if (artText.gameObject.activeSelf) |
| | | artText.color = endColor; |
| | | } |
| | | public void Resume() |
| | | { |
| | | if (controller == null) return; |
| | | controller.Resume(); |
| | | } |
| | | |
| | | timer += 1f / (float)BattleConst.skillMotionFps * speedRatio; |
| | | private void ApplyColor(Color color) |
| | | { |
| | | if (tipText.gameObject.activeSelf) |
| | | tipText.color = color; |
| | | if (artText.gameObject.activeSelf) |
| | | artText.color = color; |
| | | } |
| | | |
| | | public void ShowBackground(bool showBackground) |
| | | { |
| | | // Implement the logic to show or hide the background |
| | | background.enabled = showBackground; |
| | | } |
| | | |
| | | public void UpdatePositions(Vector2 begin, Vector2 end) |
| | | { |
| | | InitController(); |
| | | beginPos = begin; |
| | | endPos = end; |
| | | controller.beginPos = begin; |
| | | controller.endPos = end; |
| | | } |
| | | |
| | | public void UpdateScales(Vector3 beginScale, Vector3 endScale) |
| | | { |
| | | InitController(); |
| | | normalBeginScale = beginScale; |
| | | normalEndScale = endScale; |
| | | controller.normalBeginScale = beginScale; |
| | | controller.normalEndScale = endScale; |
| | | } |
| | | } |
| | |
| | | using System; |
| | | using Cysharp.Threading.Tasks; |
| | | |
| | | public class DamageContent : MonoBehaviour |
| | | public class DamageContent : MonoBehaviour, IBattleFloatingUI |
| | | { |
| | | public GameObject line; |
| | | public GameObject line; |
| | | public RectTransform parent; |
| | | |
| | | public RectTransform parent; |
| | | public Vector2 beginPos = Vector2.zero; |
| | | public Vector2 endPos = new Vector2(0, 150); |
| | | |
| | | protected List<DamageLine> damageLineList = new List<DamageLine>(); |
| | | protected List<DamageLine> damageLineList = new List<DamageLine>(); |
| | | private BattleDmgInfo battleDmgInfo; |
| | | private BattleFloatingUIController controller; |
| | | |
| | | public PositionTween posTween; |
| | | // 飘血优化:初始放大200%,透明度50%,7~8帧内缩放回100%,透明度回到100%,再往上飘14~16帧【30帧/秒】,暴击初始放大300%,缩回150% |
| | | // 战斗帧BattleConst.skillMotionFps 1秒=30帧 |
| | | |
| | | public ScaleTween scaleTween; |
| | | void Awake() |
| | | { |
| | | line.SetActive(false); |
| | | } |
| | | |
| | | private BattleDmgInfo battleDmgInfo; |
| | | private void InitController() |
| | | { |
| | | if (controller != null) return; |
| | | |
| | | void Awake() |
| | | { |
| | | line.SetActive(false); |
| | | } |
| | | RectTransform rectTransform = GetComponent<RectTransform>(); |
| | | controller = new BattleFloatingUIController(rectTransform, gameObject, ApplyColor); |
| | | |
| | | // 使用当前设置的 beginPos 和 endPos |
| | | controller.beginPos = beginPos; |
| | | controller.endPos = endPos; |
| | | // controller.scaleChangeTime = scaleChangeTime; |
| | | // controller.totalShowTime = totalShowTime; |
| | | // controller.normalBeginScale = normalBeginScale; |
| | | // controller.normalEndScale = normalEndScale; |
| | | // controller.critBeginScale = critBeginScale; |
| | | // controller.critEndScale = critEndScale; |
| | | // controller.beginColor = beginColor; |
| | | // controller.endColor = endColor; |
| | | } |
| | | |
| | | public async void SetDamage(BattleDmgInfo _damageInfo, Action _onComplete) |
| | | { |
| | | battleDmgInfo = _damageInfo; |
| | | public void SetRatio(float speed, float scale) |
| | | { |
| | | InitController(); |
| | | controller.SetRatio(speed, scale); |
| | | } |
| | | |
| | | var damages = battleDmgInfo.battleDamageList; |
| | | public async void SetDamage(BattleDmgInfo _damageInfo, Action _onComplete) |
| | | { |
| | | battleDmgInfo = _damageInfo; |
| | | |
| | | for (int i = damages.Count; i < damageLineList.Count; i++) |
| | | { |
| | | damageLineList[i].SetActive(false); |
| | | } |
| | | var damages = battleDmgInfo.battleDamageList; |
| | | |
| | | posTween.Play(_onComplete); |
| | | for (int i = damages.Count; i < damageLineList.Count; i++) |
| | | { |
| | | damageLineList[i].SetActive(false); |
| | | } |
| | | |
| | | if (battleDmgInfo.IsCrit()) |
| | | { |
| | | scaleTween.Play(); |
| | | } |
| | | // 使用控制器的Play方法 |
| | | bool isCrit = battleDmgInfo.IsCrit(); |
| | | Play(isCrit, _onComplete); |
| | | |
| | | for (int i = 0; i < damages.Count; i++) |
| | | { |
| | | if (i >= damageLineList.Count) |
| | | { |
| | | GameObject newLine = GameObject.Instantiate(line, parent); |
| | | damageLineList.Add(newLine.GetComponent<DamageLine>()); |
| | | } |
| | | damageLineList[i].SetActive(true); |
| | | damageLineList[i].SetDamage(damages[i]); |
| | | await UniTask.Delay(100); |
| | | } |
| | | } |
| | | for (int i = 0; i < damages.Count; i++) |
| | | { |
| | | if (i >= damageLineList.Count) |
| | | { |
| | | GameObject newLine = GameObject.Instantiate(line, parent); |
| | | damageLineList.Add(newLine.GetComponent<DamageLine>()); |
| | | } |
| | | damageLineList[i].SetActive(true); |
| | | damageLineList[i].SetDamage(damages[i]); |
| | | await UniTask.Delay(100); |
| | | } |
| | | } |
| | | |
| | | public void Stop() |
| | | { |
| | | posTween.Stop(); |
| | | if (battleDmgInfo.IsCrit()) |
| | | { |
| | | scaleTween.Stop(); |
| | | } |
| | | } |
| | | public void Play(bool isCrit, Action onComplete = null) |
| | | { |
| | | InitController(); |
| | | // 每次Play前更新controller的位置设置 |
| | | controller.beginPos = beginPos; |
| | | controller.endPos = endPos; |
| | | controller.Play(isCrit, onComplete); |
| | | } |
| | | |
| | | public void Resume() |
| | | { |
| | | posTween.Resume(); |
| | | if (battleDmgInfo.IsCrit()) |
| | | { |
| | | scaleTween.Resume(); |
| | | } |
| | | } |
| | | public void Run() |
| | | { |
| | | if (controller == null) return; |
| | | controller.Run(); |
| | | } |
| | | |
| | | public void Stop() |
| | | { |
| | | if (controller == null) return; |
| | | controller.Stop(); |
| | | } |
| | | |
| | | public void Resume() |
| | | { |
| | | if (controller == null) return; |
| | | controller.Resume(); |
| | | } |
| | | |
| | | private void ApplyColor(Color color) |
| | | { |
| | | for (int i = 0; i < damageLineList.Count; i++) |
| | | { |
| | | if (damageLineList[i].gameObject.activeSelf) |
| | | { |
| | | damageLineList[i].SetColor(color); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | using System.Collections; |
| | | using System.Collections.Generic; |
| | | using UnityEngine; |
| | | using UnityEngine.UI; |
| | | |
| | | public class DamageLine : MonoBehaviour |
| | | { |
| | |
| | | damageTypeLabel.SetActive(false); |
| | | damageValueLabel.text = BattleUtility.DisplayDamageNum(damage); |
| | | } |
| | | |
| | | public void SetColor(Color color) |
| | | { |
| | | var text = GetComponent<Text>(); |
| | | if (text != null) |
| | | { |
| | | text.color = color; |
| | | } |
| | | |
| | | var texts = GetComponentsInChildren<Text>(); |
| | | foreach (var t in texts) |
| | | { |
| | | t.color = color; |
| | | } |
| | | |
| | | var images = GetComponentsInChildren<Image>(); |
| | | foreach (var img in images) |
| | | { |
| | | img.color = color; |
| | | } |
| | | } |
| | | } |
| New file |
| | |
| | | using UnityEngine; |
| | | using System; |
| | | |
| | | /// <summary> |
| | | /// 战斗飘字UI接口 |
| | | /// </summary> |
| | | public interface IBattleFloatingUI |
| | | { |
| | | void Play(bool isCrit, Action onComplete = null); |
| | | void Run(); |
| | | void Stop(); |
| | | void Resume(); |
| | | void SetRatio(float speed, float scale); |
| | | } |
| New file |
| | |
| | | fileFormatVersion: 2 |
| | | guid: a7d43ddbe5932644c82d307b759d51d8 |
| | | MonoImporter: |
| | | externalObjects: {} |
| | | serializedVersion: 2 |
| | | defaultReferences: [] |
| | | executionOrder: 0 |
| | | icon: {instanceID: 0} |
| | | userData: |
| | | assetBundleName: |
| | | assetBundleVariant: |