yyl
2025-07-22 49fc368c838442a00be7bf432e2b7c26eb524fbc
125 【战斗】战斗系统 特效部分更新
6个文件已删除
9个文件已修改
843 ■■■■ 已修改文件
Main/Component/UI/Effect/ActorEffectEvent.cs 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Component/UI/Effect/ActorEffectEvent.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Component/UI/Effect/EffectPlayer.cs 188 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/EffectConfig.cs 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/SFX/SFXController.cs 223 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/SFX/SFXController.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/SFX/SFXPlayUtility.cs 288 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/SFX/SFXPlayUtility.cs.meta 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleEffectMgr.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleField/BattleField.cs 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/BattleWin.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/BulletSkillEffect.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Battle/SkillEffect/NormalSkillEffect.cs 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/UIBase/UIBase.cs 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Utility/EffectPenetrationBlocker.cs 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Component/UI/Effect/ActorEffectEvent.cs
File was deleted
Main/Component/UI/Effect/ActorEffectEvent.cs.meta
File was deleted
Main/Component/UI/Effect/EffectPlayer.cs
@@ -4,16 +4,17 @@
using Spine.Unity;
using UnityEngine;
using Spine;
using UnityEngine.UI;
public class EffectPlayer : MonoBehaviour
{
    public int effectId;
    public bool autoDestroy = false;
    public float destroyDelay = 0f;
    public EffectConfig effectConfig;
    public Action<EffectPlayer> onDestroy;
    public float speedRate = 1f;
    [HideInInspector] public Canvas canvas = null;
@@ -21,9 +22,63 @@
    protected EffectPenetrationBlocker blocker = null;
    protected bool isInit = false;
    protected List<ParticleSystem> particleList = new List<ParticleSystem>();
    protected List<Animator> animatorList = new List<Animator>();
    protected List<Renderer> rendererList = new List<Renderer>();
    protected SkeletonGraphic spineComp;
    protected void Start()
    {
        ReStart();
    }
    protected void InitCompnent()
    {
        if (effectId <= 0)
        {
            effectConfig = null;
            Debug.LogError("EffectPlayer effectId is not set");
#if UNITY_EDITOR
            UnityEditor.Selection.activeGameObject = gameObject;
            UnityEditor.EditorGUIUtility.PingObject(gameObject);
#endif
            return;
        }
        effectConfig = EffectConfig.Get(effectId);
        if (null == effectConfig)
        {
            Debug.LogError("could not find effect config, effect id is " + effectId);
#if UNITY_EDITOR
            UnityEditor.Selection.activeGameObject = gameObject;
            UnityEditor.EditorGUIUtility.PingObject(gameObject);
#endif
            return;
        }
        particleList.Clear();
        animatorList.Clear();
        rendererList.Clear();
        spineComp = null;
        if (effectConfig.isSpine != 0)
        {
            spineComp = gameObject.GetComponentInChildren<SkeletonGraphic>(true);
        }
        else
        {
            //  收集组件
            particleList.AddRange(gameObject.GetComponentsInChildren<ParticleSystem>(true));
            animatorList.AddRange(gameObject.GetComponentsInChildren<Animator>(true));
        }
        rendererList.AddRange(gameObject.GetComponentsInChildren<Renderer>(true));
    }
    public void Stop()
@@ -33,20 +88,29 @@
            DestroyImmediate(effectTarget);
            effectTarget = null;
        }
        isInit = false;
        particleList.Clear();
        animatorList.Clear();
        rendererList.Clear();
        spineComp = null;
    }
    public void Play()
    {
        if (!isActiveAndEnabled)
        {
            gameObject.SetActive(true);
        }
        ReStart();
    }
    protected void ReStart()
    {
        if (!isInit)
        {
            isInit = true;
            InitCompnent();
        }
        if (EffectMgr.Instance.IsNotShowBySetting(effectId))
        {
            return;
@@ -58,67 +122,42 @@
            effectTarget = null;
        }
        EffectConfig effectCfg = EffectConfig.Get(effectId);
        if (null == effectCfg)
        {
            return;
        }
        //    YYL TODO
        //    在这里考虑用池的话可能走配置好一点 原本的是无论如何都走池 但是实际上有些特效并不需要
        // 加载特效资源
        var effectPrefab = ResManager.Instance.LoadAsset<GameObject>("UIEffect/" + effectCfg.packageName, effectCfg.fxName);
        var effectPrefab = ResManager.Instance.LoadAsset<GameObject>("UIEffect/" + effectConfig.packageName, effectConfig.fxName);
        if (effectPrefab == null)
        {
            Debug.LogError($"加载UI特效失败: {effectCfg.packageName}");
            Debug.LogError($"加载UI特效失败: {effectConfig.packageName}");
            return;
        }
        // 实例化特效
        effectTarget = Instantiate(effectPrefab, transform);
        effectTarget.name = $"Effect_{effectCfg.fxName}";
        effectTarget.name = $"Effect_{effectConfig.fxName}";
        //  思考一下在没有挂在节点的时候
        if (null == canvas)
            canvas = GetComponentInParent<Canvas>();
        if (null == canvas)
        {
            Debug.LogError("can not find canvas for UIEffect " + effectId);
            return;
        }
        // 添加特效穿透阻挡器
        blocker = effectTarget.AddMissingComponent<EffectPenetrationBlocker>();
        blocker.parentCanvas = canvas;
        //  延迟一帧才生效
        this.DelayFrame(blocker.UpdateSortingOrder);
        // blocker.UpdateSortingOrder();
        //  如果没有canvas的话 正常是因为不在BattleWin下面的节点 意思就是当前没有显示 等到切回战斗的时候再通过BattleField.UpdateCanvas来更新
        if (canvas != null)
        {
            blocker.SetParentCanvas(canvas);
        }
        // 自动销毁
        if (autoDestroy)
        if (effectConfig.autoDestroy != 0)
        {
            Destroy(effectTarget, destroyDelay);
            Destroy(effectTarget, effectConfig.destroyDelay);
        }
    }
    public void SetSortingOrderOffset(int offset)
    {
        // 被Destroy之后effectTarget == null 为 true 但是访问内容会报错
        if (blocker != null && effectTarget != null)
        {
            blocker.sortingOrderOffset = offset;
            blocker.UpdateSortingOrder();
        }
        else
        {
            blocker = null;
            effectTarget = null;
        }
    }
    protected void OnDestroy()
    {
@@ -130,7 +169,7 @@
    }
    //  创建后的特效会自动隐藏 需要手动调用Play才能播放
    public static EffectPlayer Create(int effectId, Transform parent, bool createNewChild = false, bool _autoDestroy = true, float _destroyDelay = 5f)
    public static EffectPlayer Create(int effectId, Transform parent, bool createNewChild = false)
    {
        EffectPlayer effectPlayer = null;
@@ -144,10 +183,8 @@
        {
            effectPlayer = parent.AddMissingComponent<EffectPlayer>();
            effectPlayer.effectId = effectId;
            effectPlayer.autoDestroy = _autoDestroy;
            effectPlayer.destroyDelay = _destroyDelay;
        }
        effectPlayer.SetActive(false);
        effectPlayer.SetActive(true);
        return effectPlayer;
    }
@@ -156,22 +193,21 @@
        if (effectTarget == null) return;
        // Spine动画
        var spineGraphics = effectTarget.GetComponentsInChildren<SkeletonGraphic>(true);
        foreach (var sg in spineGraphics)
        // var spineGraphics = effectTarget.GetComponentsInChildren<SkeletonGraphic>(true);
        // foreach (var sg in spineGraphics)
        if (spineComp != null)
        {
            sg.timeScale = 0f;
            spineComp.timeScale = 0f;
        }
        // Animator动画
        var animators = effectTarget.GetComponentsInChildren<Animator>(true);
        foreach (var animator in animators)
        foreach (var animator in animatorList)
        {
            animator.speed = 0f;
        }
        // 粒子特效
        var particles = effectTarget.GetComponentsInChildren<ParticleSystem>(true);
        foreach (var ps in particles)
        foreach (var ps in particleList)
        {
            ps.Pause();
        }
@@ -181,23 +217,19 @@
    {
        if (effectTarget == null) return;
        // Spine动画
        var spineGraphics = effectTarget.GetComponentsInChildren<SkeletonGraphic>(true);
        foreach (var sg in spineGraphics)
        if (spineComp != null)
        {
            sg.timeScale = 1f;
            spineComp.timeScale = speedRate;
        }
        // Animator动画
        var animators = effectTarget.GetComponentsInChildren<Animator>(true);
        foreach (var animator in animators)
        foreach (var animator in animatorList)
        {
            animator.speed = 1f;
            animator.speed = speedRate;
        }
        // 粒子特效
        var particles = effectTarget.GetComponentsInChildren<ParticleSystem>(true);
        foreach (var ps in particles)
        foreach (var ps in particleList)
        {
            ps.Play();
        }
@@ -208,18 +240,13 @@
        if (effectTarget == null) return true;
        // Spine动画
        var spineGraphics = effectTarget.GetComponentsInChildren<SkeletonGraphic>(true);
        foreach (var sg in spineGraphics)
        if (!spineComp.AnimationState.GetCurrent(0).IsComplete)
        {
            if (!sg.AnimationState.GetCurrent(0).IsComplete)
            {
                return false;
            }
            return false;
        }
        // Animator动画
        var animators = effectTarget.GetComponentsInChildren<Animator>(true);
        foreach (var animator in animators)
        foreach (var animator in animatorList)
        {
            AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
@@ -231,8 +258,7 @@
        }
        // 粒子特效
        var particles = effectTarget.GetComponentsInChildren<ParticleSystem>(true);
        foreach (var ps in particles)
        foreach (var ps in particleList)
        {
            if (ps.IsAlive())
            {
@@ -242,4 +268,20 @@
        return true;
    }
    /// <summary>
    /// 设置遮罩(支持RectMask2D、Mask、SmoothMask等)
    /// </summary>
    public void SetMask(RectTransform maskArea = null)
    {
        if (effectTarget == null || blocker == null)
            return;
        // 优先使用传入的maskArea
        if (maskArea != null)
        {
            blocker.PerformMask(maskArea);
            return;
        }
    }
}
Main/Config/Configs/EffectConfig.cs
@@ -1,6 +1,6 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           Friday, June 27, 2025
//    [  Date ]:           2025年7月22日
//--------------------------------------------------------
using System.Collections.Generic;
@@ -15,13 +15,13 @@
    public int id;
    public string packageName;
    public int isSpine;
    public string fxName;
    public int job;
    public int audio;
    public int stopImmediate;
    public int setParent;
    public string nodeName;
    public int notShow;
    public int autoDestroy;
    public float destroyDelay;
    public override int LoadKey(string _key)
    {
@@ -37,19 +37,19 @@
            packageName = tables[1];
            fxName = tables[2];
            int.TryParse(tables[2],out isSpine);
            int.TryParse(tables[3],out job);
            fxName = tables[3];
            int.TryParse(tables[4],out audio); 
            int.TryParse(tables[5],out stopImmediate);
            nodeName = tables[5];
            int.TryParse(tables[6],out setParent);
            int.TryParse(tables[6],out notShow);
            nodeName = tables[7];
            int.TryParse(tables[7],out autoDestroy);
            int.TryParse(tables[8],out notShow);
            float.TryParse(tables[8],out destroyDelay);
        }
        catch (Exception exception)
        {
Main/Core/SFX/SFXController.cs
File was deleted
Main/Core/SFX/SFXController.cs.meta
File was deleted
Main/Core/SFX/SFXPlayUtility.cs
File was deleted
Main/Core/SFX/SFXPlayUtility.cs.meta
File was deleted
Main/System/Battle/BattleEffectMgr.cs
@@ -48,12 +48,11 @@
            effectDict[effectId] = new List<EffectPlayer>();
        }
        EffectPlayer effectPlayer = EffectPlayer.Create(effectId, parent, true, false);
        EffectPlayer effectPlayer = EffectPlayer.Create(effectId, parent);
        effectPlayer.onDestroy = OnEffectDestroy;
        if (effectPlayer != null)
        {
            effectDict[effectId].Add(effectPlayer);
            effectPlayer.Play();
        }
        return effectPlayer;
    }
Main/System/Battle/BattleField/BattleField.cs
@@ -290,4 +290,17 @@
        // return round > xxx;
        return false;
    }
    public void UpdateCanvas(Canvas canvas)
    {
        EffectPenetrationBlocker[] blockers = battleRootNode.GetComponentsInChildren<EffectPenetrationBlocker>(true);
        if (null != blockers)
        {
            foreach (var blocker in blockers)
            {
                blocker.SetParentCanvas(canvas);
            }
        }
    }
}
Main/System/Battle/BattleWin.cs
@@ -35,10 +35,7 @@
    protected override void OnPreOpen()
    {
        base.OnPreOpen();
        SetBattleField(BattleManager.Instance.storyBattleField);
        // SetBattleField(BattleManager.Instance.storyBattleField);
    }
    protected override void OnPreClose()
@@ -96,5 +93,6 @@
        }
        ui.SetBattleField(battleField);
        battleField.UpdateCanvas(canvas);
    }
}
Main/System/Battle/SkillEffect/BulletSkillEffect.cs
@@ -76,7 +76,6 @@
    {
        EffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.EffectId, caster.effectNode);
        effectPlayer.Play();
        RectTransform effectTrans = effectPlayer.transform as RectTransform;
@@ -88,7 +87,7 @@
            //  击中就销毁子弹
            caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.EffectId, effectPlayer);
            //  播放子弹爆炸特效
            caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.ExplotionEffectId, target).Play();
            caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.ExplotionEffectId, target);
        });
        caster.battleField.battleTweenMgr.OnPlayTween(tween);
Main/System/Battle/SkillEffect/NormalSkillEffect.cs
@@ -21,14 +21,15 @@
    public override void Play(Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> _onHit)
    {
        Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> onHitFormation = (_hitIndex, _hurtList) =>
        // 特效炸开在阵容的中间的回调
        Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> onHitLineUpCenter = (_hitIndex, _hurtList) =>
        {
            _onHit?.Invoke(_hitIndex, tagUseSkillAttack.HurtList.ToList());
        };
        if (skillConfig.effectAnchor == SkillEffectAnchor.Caster)
        {
            CastInTarget(caster.heroGo.transform as RectTransform, onHitFormation);
            CastInTarget(caster.heroGo.transform as RectTransform, onHitLineUpCenter);
        }
        else if (skillConfig.effectAnchor == SkillEffectAnchor.Target)
        {
@@ -53,11 +54,11 @@
        }
        else if (skillConfig.effectAnchor == SkillEffectAnchor.AlliesCenter)
        {
            CastInTarget(caster.battleField.GetTeamNode(caster.Camp), onHitFormation);
            CastInTarget(caster.battleField.GetTeamNode(caster.Camp), onHitLineUpCenter);
        }
        else if (skillConfig.effectAnchor == SkillEffectAnchor.EnemiesCenter)
        {
            CastInTarget(caster.battleField.GetTeamNode(caster.Camp == BattleCamp.Blue ? BattleCamp.Red : BattleCamp.Blue), onHitFormation);
            CastInTarget(caster.battleField.GetTeamNode(caster.Camp == BattleCamp.Blue ? BattleCamp.Red : BattleCamp.Blue), onHitLineUpCenter);
        }
        else
        {
@@ -69,8 +70,6 @@
    {
        EffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.EffectId, caster.effectNode);
        effectPlayer.Play();
        RectTransform effectTrans = effectPlayer.transform as RectTransform;
        _onHit?.Invoke(0, null);
@@ -78,7 +77,7 @@
        //  销毁自身上的特效应该是等特效播放完毕之后
        // caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.EffectId, effectPlayer);
        //  播放受击特效
        caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.ExplotionEffectId, target).Play();
        caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.ExplotionEffectId, target);
    }
Main/System/UIBase/UIBase.cs
@@ -358,19 +358,12 @@
    /// <param name="autoDestroy">是否自动销毁,默认为true</param>
    /// <param name="destroyDelay">自动销毁延迟时间,默认为5秒</param>
    /// <returns>特效游戏对象</returns>
    public EffectPlayer PlayUIEffect(int id, Transform parent = null, bool autoDestroy = true, float destroyDelay = 5f)
    public EffectPlayer PlayUIEffect(int id, Transform parent = null)
    {
        // 使用默认值
        if (parent == null) parent = transform;
        EffectPlayer player = parent.gameObject.AddComponent<EffectPlayer>();
        player.effectId = id;
        player.autoDestroy = autoDestroy;
        player.destroyDelay = destroyDelay;
        player.canvas = canvas;
        return player;
        return EffectPlayer.Create(id, parent, false);
    }
    
    #endregion
Main/Utility/EffectPenetrationBlocker.cs
@@ -133,7 +133,30 @@
        parentCanvas = canvas;
        if (autoAdjustSorting)
        {
            UpdateSortingOrder();
            this.DelayFrame(UpdateSortingOrder);
        }
    }
    /// <summary>
    /// 应用遮罩区域(RectTransform),可用于裁剪特效
    /// </summary>
    public void PerformMask(RectTransform maskRect)
    {
        // 这里只是示例,实际可根据你的Shader或特效材质做裁剪
        foreach (Renderer renderer in effectRenderers)
        {
            if (renderer != null && renderer.material != null && maskRect != null)
            {
                Vector3[] corners = new Vector3[4];
                maskRect.GetWorldCorners(corners);
                Vector4 clipRect = new Vector4(corners[0].x, corners[0].y, corners[2].x, corners[2].y);
                renderer.material.SetVector("_ClipRect", clipRect);
                renderer.material.SetFloat("_UseClipRect", 1);
            }
            else if (renderer != null && renderer.material != null)
            {
                renderer.material.SetFloat("_UseClipRect", 0);
            }
        }
    }