hch
昨天 0333a7ba48bb5c5c28d8eaf1d94e5dd6d990534f
Main/System/Battle/SkillEffect/BulletSkillEffect.cs
@@ -11,91 +11,516 @@
    // protected BattleObject caster;
    // protected List<BattleObject> targets; // 目标列表
    public BulletSkillEffect(SkillConfig _skillConfig, BattleObject _caster, H0604_tagUseSkillAttack _tagUseSkillAttack)
        : base(_skillConfig, _caster, _tagUseSkillAttack)
    protected List<BulletCurve> bulletCurves = new List<BulletCurve>();
    // 散射技能击中计数器,用于判断是否所有目标都已击中
    private int scatterHitCount = 0;
    private int scatterTotalTargets = 0;
    public BulletSkillEffect(SkillBase _skillBase, SkillConfig _skillConfig, SkillSkinConfig _skillSkinConfig, BattleObject _caster, HB427_tagSCUseSkill _tagUseSkillAttack)
        : base(_skillBase, _skillConfig, _skillSkinConfig, _caster, _tagUseSkillAttack)
    {
    }
    public override void Play(Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> _onHit)
    public override void OnMiddleFrameEnd(int times, int index)
    {
        // Caster, //在施法者上
        // Target, //在目标上
        // AlliesCenter,// 在友方中心
        // EnemiesCenter,// 在敌方中心
        Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> onHitFormation = (_hitIndex, _hurtList) =>
        base.OnMiddleFrameEnd(times, index);
        //  弹射 另外的做法了
        if (skillSkinConfig.effectType == SkillEffectType.Bullet && skillSkinConfig.BulletPath == 4)
        {
            _onHit?.Invoke(_hitIndex, tagUseSkillAttack.HurtList.ToList());
        };
        if (skillConfig.effectAnchor == SkillEffectAnchor.Caster)
        {
            // 不可能子弹射向自己吧
            Debug.LogError("子弹技能特效不能锚定在施法者上 skillConfig.effectAnchor");
            _onHit?.Invoke(0, default);
        }
        else if (skillConfig.effectAnchor == SkillEffectAnchor.Target)
        {
            if (tagUseSkillAttack == null || tagUseSkillAttack.HurtList.Length <= 0)
            var hurt = tagUseSkillAttack.HurtList[0];
            BattleObject targetObject = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
            if (targetObject == null)
            {
                Debug.LogError("子弹技能特效没有目标 tagUseSkillAttack.HurtList.Length <= 0");
                _onHit?.Invoke(0, default);
                Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
                return;
            }
            ShotToTarget(targetObject, index);
        }
        //  普通的做法 区分打向阵营或者打向个体
        else
        {
            //  区分散射跟范围攻击
            if (skillConfig.Scattering == 1)
            {
                //  散射
                ScatterShot(index);
            }
            else
            {
                switch (skillConfig.TagAim)
                {
                    case 0:
                        AllAreaShoting(index);
                        break;
                    case 1:
                        OneTargetShoting(index);
                        break;
                    case 2:
                        FrontRowShoting(index);
                        break;
                    case 3:
                        BackRowShoting(index);
                        break;
                    case 4:
                        VerticalRowShoting(index);
                        break;
                    case 5:
                        SelfShoting(index);
                        break;
                    default:
                        Debug.LogError("子弹特效没有配置正确的TagAim,强制结束子弹特效 TagAim: " + skillConfig.TagAim);
                        ForceFinished();
                        break;
                }
            }
        }
    }
    // 0   全部范围:
    private void AllAreaShoting(int index)
    {
        if (skillConfig.TagCount == 0 || skillConfig.TagCount >= 6)
        {
            // 若TagCount目标个数为0或6,根据TagFriendly敌我配置,代表作用于敌方全体或我方全体,此时主目标为敌我站位中的2号位置
            BattleCamp battleCamp = skillConfig.TagFriendly != 0 ? caster.Camp : caster.GetEnemyCamp();
            ShotToIndex(battleCamp, 1, index);
        }
        else
        {
            // 若TagCount目标个数为1~5个,代表随机作用于敌方或我方x个武将,此时所有被随机到的对象都为主目标(施法位置会用客户端配置)
            ShotEachTargets(index);
        }
    }
    // 1    对位:
    private void OneTargetShoting(int index)
    {
        // 默认只选1个,对位规则为A1优先打B1,A2优先打B2,A3优先打B3,对位目标死亡时,优先前排,
        // 比如B2已经死亡,那么A2将优先打B1,前排1、2、3号位置全部死亡之后才开始选择后排4、5、6号位置,
        // 对位只可选1个目标,即主目标
        if (tagUseSkillAttack.HurtList.Length > 1)
        {
            Debug.LogError("服务器 对位攻击目标数量错误,应该只有一个目标 技能id" + skillConfig.SkillID);
        }
        var hurt = tagUseSkillAttack.HurtList[0];
        BattleObject targetObject = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
        if (targetObject == null)
        {
            Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
            return;
        }
        ShotToTarget(targetObject, index);
    }
    // 2    前排:
    private void FrontRowShoting(int index)
    {
        // 1、2、3号位为前排,默认2号位置为主目标,当1、2、3号位置角色全部死亡,前排将替换成后排,5号位置变更为主目标,
        // 若配置TagAffect细分目标,且人数小于3,则所有被选择目标均为主目标(施法位置会用客户端配置)
        // (即前排默认2号位或5号位规则无效,实际作用多少人就是多少个主目标)
        BattleCamp battleCamp = skillConfig.TagFriendly != 0 ? caster.Camp : caster.GetEnemyCamp();
        if (skillConfig.TagAffect != 0 || skillConfig.TagCount < 3)
        {
            ShotEachTargets(index);
        }
        else
        {
            int targetIndex = int.MaxValue;
            int minimumIndex = int.MaxValue;
            foreach (var hurt in tagUseSkillAttack.HurtList)
            {
                BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
                if (target == null)
                {
                    Debug.LogError("子弹技能特效目标为空 target == null ObjId : " + hurt.ObjID);
                    Debug.LogError("特效目标为空 target == null ObjId : " + hurt.ObjID);
                    continue;
                }
                ShotToTarget(target.heroGo.transform as RectTransform, (index, list) => _onHit(0, new List<H0604_tagUseSkillAttack.tagSkillHurtObj>() { hurt }));
                minimumIndex = Mathf.Min(target.GetPositionNum(), minimumIndex);
                if (target.Camp == battleCamp && target.GetPositionNum() < 3)
                {
                    targetIndex = 1;
                    break;
                }
            }
            if (targetIndex == int.MaxValue)
            {
                targetIndex = (minimumIndex >= 3) ? 4 : 1;
            }
            else
            {
                targetIndex = 1;
            }
            ShotToIndex(battleCamp, targetIndex, index);
        }
        else if (skillConfig.effectAnchor == SkillEffectAnchor.AlliesCenter)
        {
            ShotToTarget(caster.battleField.GetTeamNode(caster.Camp), onHitFormation);
        }
        else if (skillConfig.effectAnchor == SkillEffectAnchor.EnemiesCenter)
        {
            ShotToTarget(caster.battleField.GetTeamNode(caster.Camp == BattleCamp.Blue ? BattleCamp.Red : BattleCamp.Blue), onHitFormation);
        }
        else
        {
            Debug.LogError("未知的技能特效锚点类型: " + skillConfig.effectAnchor);
        }
    }
    protected void ShotToTarget(RectTransform target, Action<int, List<H0604_tagUseSkillAttack.tagSkillHurtObj>> _onHit)
    private void ShotToIndex(BattleCamp camp, int targetIndex, int bulletIndex)
    {
        EffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.EffectId, caster.effectNode);
        effectPlayer.Play();
        RectTransform targetTransform = caster.battleField.GetTeamNode(camp, targetIndex);
        BattleEffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster, skillSkinConfig.BulletEffectId, caster.GetRectTransform(), caster.Camp, caster.GetModelScale());
        RectTransform effectTrans = effectPlayer.transform as RectTransform;
        var tween = BattleUtility.MoveToTarget(effectTrans, target, Vector2.zero, skillConfig.FlyTime, () =>
        var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, skillSkinConfig, effectPlayer, targetTransform, tagUseSkillAttack.HurtList.ToList(), bulletIndex, (index, hitList) =>
        {
            // 表现子弹飞行到目标位置
            _onHit?.Invoke(0, null);
            if (isFinish)
                return;
            // 击中就销毁子弹
            caster.battleField.battleEffectMgr.RemoveEffect(skillSkinConfig.BulletEffectId, effectPlayer);
            // 播放子弹爆炸特效
            //  击中就销毁子弹
            caster.battleField.battleEffectMgr.RemoveEffect(skillConfig.EffectId, effectPlayer);
            //  播放子弹爆炸特效
            caster.battleField.battleEffectMgr.PlayEffect(caster.ObjID, skillConfig.ExplotionEffectId, target).Play();
            BattleCamp battleCamp = skillConfig.TagFriendly != 0 ? caster.Camp : caster.GetEnemyCamp();
            //  首先是目标身上爆炸
            PlayExplosionEffect(skillSkinConfig.ExplosionEffectId, targetTransform, caster.Camp, 1f);
            PlayExplosionEffect(skillSkinConfig.ExplosionEffect2, targetTransform, caster.Camp, 1f);
            foreach (var hurt in hitList)
            {
                BattleObject targetObj = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
                if (targetObj == null)
                {
                    Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
                    continue;
                }
                PlayExplosionEffect(skillSkinConfig.ExplosionEffect3, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                PlayExplosionEffect(skillSkinConfig.ExplosionEffect4, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
            }
            // 表现子弹飞行到目标位置
            onHit?.Invoke(index, hitList);
            isFinish = true;
        });
        caster.battleField.battleTweenMgr.OnPlayTween(tween);
        bulletCurves.Add(bulletCurve);
    }
    // 3    后排:
    private void BackRowShoting(int index)
    {
        // 4、5、6号位为后排,默认5号位置为主目标,当4、5、6号位置角色全部死亡,后排排将替换成前排,2号位置变更为主目标,
        // 若配置TagAffect细分目标,且人数小于3,则所有被选择目标均为主目标(施法位置会用客户端配置)
        // (即前排默认2号位或5号位规则无效,实际作用多少人就是多少个主目标)
        BattleCamp battleCamp = skillConfig.TagFriendly != 0 ? caster.Camp : caster.GetEnemyCamp();
        if (skillConfig.TagAffect != 0 || skillConfig.TagCount < 3)
        {
            ShotEachTargets(index);
        }
        else
        {
            int targetIndex = int.MaxValue;
            int maxinumIndex = int.MinValue;
            foreach (var hurt in tagUseSkillAttack.HurtList)
            {
                BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
                if (target == null)
                {
                    Debug.LogError("特效目标为空 target == null ObjId : " + hurt.ObjID);
                    continue;
                }
                if (target.Camp == battleCamp && target.GetPositionNum() > 3)
                {
                    targetIndex = 4;
                    break;
                }
                maxinumIndex = Mathf.Max(target.GetPositionNum(), maxinumIndex);
            }
            if (targetIndex == int.MaxValue)
            {
                targetIndex = (maxinumIndex < 3) ? 1 : 4;
            }
            else
            {
                targetIndex = 4;
            }
            ShotToIndex(battleCamp, targetIndex, index);
        }
    }
    // 4    纵排:
    private void VerticalRowShoting(int index)
    {
        // 纵排分别为1、4,2、5,3、6,三组纵排,按对位规则选择,默认1号、2号或3号为主目标,前排1、2、3号位置全部死完后,4号、5号或6号为主目标
        BattleCamp battleCamp = skillConfig.TagFriendly != 0 ? caster.Camp : caster.GetEnemyCamp();
        //  攻击mininumIndex目标
        int minimumIndex = int.MaxValue;
        foreach (var hurt in tagUseSkillAttack.HurtList)
        {
            BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
            if (target == null)
            {
                Debug.LogError("特效目标为空 target == null ObjId : " + hurt.ObjID);
                continue;
            }
            minimumIndex = Mathf.Min(target.GetPositionNum(), minimumIndex);
        }
        if (minimumIndex != int.MaxValue)
        {
            ShotToIndex(battleCamp, minimumIndex, index);
        }
        else
        {
            Debug.LogError("纵排攻击没有目标 强制结束子弹特效");
            ForceFinished();
        }
    }
    // 5    自己:
    private void SelfShoting(int index)
    {
        // 默认只选自己,自己为主目标
        ShotToIndex(caster.Camp, caster.GetPositionNum(), index);
    }
    //  散射
    private void ScatterShot(int index)
    {
        // 只在第一次发射时初始化散射计数器
        if (index == 0)
        {
            scatterHitCount = 0;
            // 总击中数 = 发射次数 × 目标数量
            scatterTotalTargets = skillSkinConfig.ActiveFrames.Length * tagUseSkillAttack.HurtList.Length;
        }
        // 处理散射逻辑
        for (int i = 0; i < tagUseSkillAttack.HurtList.Length; i++)
        {
            var hurt = tagUseSkillAttack.HurtList[i];
            BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
            if (target == null)
            {
                Debug.LogError("特效目标为空 target == null ObjId : " + hurt.ObjID);
                // 目标为空时减少对应发射次数的总目标数
                if (index == 0) scatterTotalTargets--;
                continue;
            }
            ScatterShot(target, hurt, index, i);
        }
    }
    private void ScatterShot(BattleObject target, HB427_tagSCUseSkill.tagSCUseSkillHurt hurt, int bulletIndex, int order)
    {
        BattleEffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster, skillSkinConfig.BulletEffectId, caster.GetRectTransform(), caster.Camp, caster.GetModelScale());
        bool shotToSelf = target.ObjID == caster.ObjID;
        effectPlayer.Alpha = shotToSelf ? 0f : 1f;
        var tempOrder = order;
        var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, skillSkinConfig, effectPlayer, target.GetRectTransform(),
            new List<HB427_tagSCUseSkill.tagSCUseSkillHurt> { hurt }, bulletIndex, (index, hitList) =>
        {
            foreach (var hurt in hitList)
            {
                BattleObject targetObj = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
                if (targetObj == null)
                {
                    Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
                    continue;
                }
                PlayExplosionEffect(skillSkinConfig.ExplosionEffectId, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                PlayExplosionEffect(skillSkinConfig.ExplosionEffect2, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                PlayExplosionEffect(skillSkinConfig.ExplosionEffect3, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                PlayExplosionEffect(skillSkinConfig.ExplosionEffect4, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
            }
            // 表现子弹飞行到目标位置
            onHit?.Invoke(index, hitList);
            // 击中就销毁子弹
            caster.battleField.battleEffectMgr.RemoveEffect(skillSkinConfig.BulletEffectId, effectPlayer);
            // 增加散射击中计数
            scatterHitCount++;
            // 判断是否所有发射次数的所有目标都已击中
            if (scatterHitCount >= scatterTotalTargets)
            {
                isFinish = true;
            }
        });
        bulletCurves.Add(bulletCurve);
    }
    protected void ShotToTarget(BattleObject target, int bulletIndex)
    {
        BattleEffectPlayer effectPlayer = caster.battleField.battleEffectMgr.PlayEffect(caster, skillSkinConfig.BulletEffectId, caster.GetRectTransform(), caster.Camp, caster.GetModelScale());
        bool shotToSelf = target.ObjID == caster.ObjID;
        effectPlayer.Alpha = shotToSelf ? 0f : 1f;
        int bounceHitIndex = 0;
        int tempBulletIndex = bulletIndex;
        var bulletCurve = BulletCurveFactory.CreateBulletCurve(caster, skillConfig, skillSkinConfig, effectPlayer, target.GetRectTransform(), tagUseSkillAttack.HurtList.ToList(), bulletIndex, (index, hitList) =>
        {
            if (skillSkinConfig.BulletPath == 4)
            {
                if (bounceHitIndex >= hitList.Count)
                {
                    return;
                }
                var hurt = hitList[bounceHitIndex++];
                BattleObject targetObj = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
                if (targetObj != null)
                {
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffectId, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffect2, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffect3, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffect4, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                }
                else
                {
                    Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
                }
                // 表现子弹飞行到目标位置
                onHit?.Invoke(index, new List<HB427_tagSCUseSkill.tagSCUseSkillHurt> { hurt });
                if (bounceHitIndex >= tagUseSkillAttack.HurtList.Length)
                {
                    caster.battleField.battleEffectMgr.RemoveEffect(skillSkinConfig.BulletEffectId, effectPlayer);
                }
                if (isFinish)
                    return;
                if (tempBulletIndex >= skillSkinConfig.ActiveFrames.Length - 1 && bounceHitIndex >= hitList.Count)
                {
                    isFinish = true;
                }
            }
            else
            {
                foreach (var hurt in hitList)
                {
                    BattleObject targetObj = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
                    if (targetObj == null)
                    {
                        Debug.LogError("目标为空 target == null ObjId : " + hurt.ObjID);
                        continue;
                    }
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffectId, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffect2, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffect3, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                    PlayExplosionEffect(skillSkinConfig.ExplosionEffect4, targetObj.GetTransform(), caster.Camp, targetObj.GetModelScale());
                }
                // 表现子弹飞行到目标位置
                onHit?.Invoke(index, hitList);
                // 击中就销毁子弹
                caster.battleField.battleEffectMgr.RemoveEffect(skillSkinConfig.BulletEffectId, effectPlayer);
                if (isFinish)
                    return;
                if (bulletIndex >= skillSkinConfig.ActiveFrames.Length - 1)
                {
                    isFinish = true;
                }
            }
        });
        bulletCurves.Add(bulletCurve);
    }
    protected void PlayExplosionEffect(int effectId, Transform parent, BattleCamp camp, float _scaleRatio)
    {
        if (effectId <= 0)
            return;
        var effect = caster.battleField.battleEffectMgr.PlayEffect(caster, effectId, parent, camp, _scaleRatio);
        if (effect != null)
        {
            effect.transform.localRotation = parent.localRotation;
            if (effect.transform.localScale.x < 0f)
            {
                effect.transform.localRotation *= Quaternion.Euler(0, 180, 0);
            }
        }
    }
    private void ShotEachTargets(int index)
    {
        for (int i = 0; i < tagUseSkillAttack.HurtList.Length; i++)
        {
            var hurt = tagUseSkillAttack.HurtList[i];
            BattleObject target = caster.battleField.battleObjMgr.GetBattleObject((int)hurt.ObjID);
            if (target == null)
            {
                Debug.LogError("特效目标为空 target == null ObjId : " + hurt.ObjID);
                continue;
            }
            ShotToTarget(target, index);
        }
    }
    public override void Run()
    {
        foreach (var bulletCurve in bulletCurves)
        {
            if (!bulletCurve.IsFinished)
                bulletCurve.Run();
        }
    }
    public override void ForceFinished()
    {
        base.ForceFinished();
        foreach (var bulletCurve in bulletCurves)
        {
            bulletCurve.ForceFinish();
        }
    }
    public override bool IsFinished()
    {
        bool isCurveFinish = bulletCurves.Count <= 0;
        foreach (var bulletCurve in bulletCurves)
        {
            isCurveFinish |= bulletCurve.IsFinished;
        }
        return isCurveFinish && base.IsFinished();
    }
}