using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using AOT.PostProcess.BlackArea; using Gameplay.Building; using Gameplay.Building.Data; using Gameplay.Building.Impl; using Gameplay.Bullet.NormalAttack; using Gameplay.PostProcess.BlackArea; using Gameplay.Summon; using Gameplay.Unit; using Gameplay.Unit.Data; using Gameplay.Vehicle.Impl; using PhxhSDK; using UnityEngine; using Random = UnityEngine.Random; namespace Gameplay.Bullet { using cfg.BuffCfg; using cfg.BulletCfg; using Character; using Framework; using Buff; using Skill; using Area; using Common; using cfg.SkillCfg; public class BulletManager { private static BulletManager _instance; public static BulletManager instance { get { if (_instance == null) { DebugUtil.LogError("Bullet尚未初始化,请先初始化"); return null; } return _instance; } } public static BulletManager CreateInstance() { if (_instance != null) { DebugUtil.LogError("请勿重复创建BulletManager"); return _instance; } _instance = new BulletManager(); return _instance; } public GameObject rootObj; private readonly List _bullets; private readonly List _readyBullets; private readonly Dictionary _loadCount; private readonly List _flyingNormalAttackBullets = new List(); private Dictionary> _normalAttackBulletPool = new Dictionary>(); private BulletManager() { _bullets = new List(); _readyBullets = new List(); _loadCount = new Dictionary(); } public void Init() { rootObj = new GameObject("BulletManager"); } public void RecordLoadCount(string path) { if (_loadCount.ContainsKey(path)) { _loadCount[path]++; } else { _loadCount.Add(path, 1); } } public void Dispose() { // 进行资源清理 foreach (var kv in _loadCount) { var path = kv.Key; var count = kv.Value; for (var i = 0; i < count; ++i) { AssetManager.Instance.Unload(path); } } foreach (var kv in _normalAttackBulletPool) { var stack = kv.Value; while (stack.Count > 0) { var bullet = stack.Pop(); bullet.Dispose(); } } _normalAttackBulletPool.Clear(); for (int i = 0; i < _flyingNormalAttackBullets.Count; i++) { var bullet = _flyingNormalAttackBullets[i]; bullet.Dispose(); } _bullets.Clear(); _readyBullets.Clear(); _loadCount.Clear(); rootObj.Destroy(); _instance = null; } public void LogicUpdate(float dt) { for (var i = 0; i < _readyBullets.Count; ++i) { var bullet = _readyBullets[i]; bullet.Init(); } _bullets.AddRange(_readyBullets); _readyBullets.Clear(); for (var i = 0; i < _bullets.Count; ++i) { var bullet = _bullets[i]; // 技能特殊暂停 if (SkillManager.instance.needSkillPaused && bullet.sender != SkillManager.instance.inSkillingUnit) { continue; } bullet.LogicUpdate(dt); if (bullet.needRemove) { _bullets.RemoveAt(i); i--; } } for (var i = 0; i < _flyingNormalAttackBullets.Count; ++i) { var bullet = _flyingNormalAttackBullets[i]; bullet.LogicUpdate(dt); if (bullet.isFinished) { _ReturnNormalAttackBullet(bullet); _flyingNormalAttackBullets.RemoveAt(i); i--; } } } private void _ReturnNormalAttackBullet(NormalAttackBullet bullet) { bullet.Hide(); if (!_normalAttackBulletPool.TryGetValue(bullet.effectId, out var stack)) { stack = new Stack(); _normalAttackBulletPool.Add(bullet.effectId, stack); } stack.Push(bullet); } /// /// 普通攻击走特殊处理 /// /// /// public void DoNormalShoot(GameUnit sender, GameUnit receiver, bool noMiss) { // _ = AudioManager.Instance.PlayAudio(1001, sender.transData.pos); // 理论上可以走立马销毁的子弹逻辑,但是这里处理成直接addbuff,减少性能消耗 // // 造成伤害 // var normalDamageBuff = BuffManager.instance.CreateBuffById(sender, InnerBuffID.NORMAL_DAMAGE); // BuffManager.instance.AddBuff(receiver, normalDamageBuff); // // // 打击士气 // var moraleDamageBuff = BuffManager.instance.CreateBuffById(sender, InnerBuffID.MORALE_DAMAGE); // BuffManager.instance.AddBuff(receiver, moraleDamageBuff); NormalAttackBullet bullet = null; switch (sender.gameunitType) { case EGameUnitType.Character: bullet = _HandleCharacterNormalAttack(sender, receiver, noMiss); break; case EGameUnitType.Vehicle: bullet = _HandleVehicleNormalAttack(sender, receiver, noMiss); break; case EGameUnitType.Building: bullet = _HandleBuildNormalAttack(sender, receiver, noMiss); break; default: DebugUtil.LogError("暂未支持的GameUnitType:{0}", sender.gameunitType); break; } if (bullet == null) { DebugUtil.LogError("普通攻击子弹创建失败"); return; } _TriggerNormalAttack(sender); bullet.Show(); _flyingNormalAttackBullets.Add(bullet); } private void _TriggerNormalAttack(GameUnit sender) { var skillManager = SkillManager.instance.GetUnitSkillManager(sender); if (skillManager != null) { skillManager.TriggerNormalAttack(); } var buffManager = sender.buffManager; if (buffManager != null) { buffManager.TriggerNormalAttack(); } } private NormalAttackBullet _HandleBuildNormalAttack(GameUnit unit, GameUnit targetUnit, bool noMiss) { var unitBuild = unit as UnitBuild; if (unitBuild == null) { DebugUtil.LogError("非UnitBuild类型,无法进行普通攻击"); return null; } switch (unitBuild.buildType) { case EFightBuildType.Pillbox: return _HandleBuildPillBoxNormalAttack(unit, targetUnit, noMiss); default: DebugUtil.LogError("暂未支持的Build类型:{0}", unitBuild.buildType); break; } return null; } private NormalAttackBullet _HandleVehicleNormalAttack(GameUnit unit, GameUnit targetUnit, bool noMiss) { var unitVehicle = unit as NormalVehicle; if (unitVehicle == null) { DebugUtil.LogError("非Vehicle类型,无法进行普通攻击"); return null; } var weaponConfig = unitVehicle.battery.rawConfig; if (weaponConfig == null) { DebugUtil.LogError("载具炮台配置为空,无法进行普通攻击"); return null; } return _CommonCreateBullet(unit, targetUnit, noMiss, weaponConfig.FlyEffectId, weaponConfig.BulletFlySpeed, weaponConfig.MissHitGroundEffectId, weaponConfig.CriticalHitEffectId, weaponConfig.HitEffectId); } private NormalAttackBullet _HandleBuildPillBoxNormalAttack(GameUnit unit, GameUnit targetUnit, bool noMiss) { var unitBuildPillBox = unit as BuildPillBox; if (unitBuildPillBox == null) { DebugUtil.LogError("非BuildPillBox类型,无法进行普通攻击"); return null; } var weaponConfig = unitBuildPillBox.weaponConfig; if (weaponConfig == null) { DebugUtil.LogError("武器配置为空,无法进行普通攻击"); return null; } return _CommonCreateBullet(unit, targetUnit, noMiss, weaponConfig.FlyEffectId, weaponConfig.BulletFlySpeed, weaponConfig.MissHitGroundEffectId, weaponConfig.CriticalHitEffectId, weaponConfig.HitEffectId); } private NormalAttackBullet _HandleCharacterNormalAttack(GameUnit unit, GameUnit targetUnit, bool noMiss) { var unitCharacter = unit as Character; if (unitCharacter == null) { DebugUtil.LogError("非Character类型,无法进行普通攻击"); return null; } var weaponConfig = unitCharacter.weapon.rawConfig; if (weaponConfig == null) { DebugUtil.LogError("武器配置为空,无法进行普通攻击"); return null; } return _CommonCreateBullet(unit, targetUnit, noMiss, weaponConfig.FlyEffectId, weaponConfig.BulletFlySpeed, weaponConfig.MissHitGroundEffectId, weaponConfig.CriticalHitEffectId, weaponConfig.HitEffectId); } private NormalAttackBullet _CommonCreateBullet(GameUnit sender, GameUnit targetUnit, bool noMiss, int flyEffectId, float flySpeed, int hitGroundEffectId, int criticalHitEffectId, int normalHitEffectId) { var bulletEffectId = flyEffectId; var bullet = _GetOrCreateNormalAttackBullet(bulletEffectId); var emitTrans = NormalAttackHelper.GetEmitTrans(sender); bullet.SetBaseInfo(sender, flySpeed, emitTrans); var distanceToTarget = AreaManager.instance.GetDistance(sender.transData.cellIndex, targetUnit.transData.cellIndex); var hitRate = sender.fightData.GetAttackRate(distanceToTarget); var randomValue = UnityEngine.Random.Range(0f, 1f); if (randomValue > hitRate && !noMiss) { // miss var missPos = NormalAttackHelper.GetMissHitPos(targetUnit); bullet.SetMiss(missPos, hitGroundEffectId); } else { var criticalRate = sender.fightData.criticalRate; var randomCritical = UnityEngine.Random.Range(0f, 1f); if (randomCritical < criticalRate) { // 暴击 var hitTrans = NormalAttackHelper.GetCriticalHitTrans(targetUnit); bullet.SetTarget(targetUnit, hitTrans, criticalHitEffectId, EBulletHitType.Critical); } else { // 普通攻击 var hitTrans = NormalAttackHelper.GetCriticalHitTrans(targetUnit); bullet.SetTarget(targetUnit, hitTrans, normalHitEffectId, EBulletHitType.Normal); } } return bullet; } private NormalAttackBullet _GetOrCreateNormalAttackBullet(int effectId) { if (_normalAttackBulletPool.TryGetValue(effectId, out var stack)) { if (stack.Count > 0) { return stack.Pop(); } } var bullet = new NormalAttackBullet(effectId); bullet.CreateView(rootObj.transform); return bullet; } public ViewBullet EmitBullet(DataBullet bulletConfig, GameUnit targetUnit, GameUnit sender) { ViewBullet result = null; switch (bulletConfig.BulletType) { case EBulletType.DIRECT_DAMAGE: // 直接造成伤害 AddBuffs2Unit(targetUnit, sender, bulletConfig); break; case EBulletType.POS_LOCK: // 锁地板 result = _EmitLockPosBullet(targetUnit.transData.cellIndex, sender, bulletConfig); break; case EBulletType.UNIT_LOCK: // 锁单位 result = _EmitLockUnitBullet(targetUnit, sender, bulletConfig); break; default: DebugUtil.LogError("暂未实现的子弹类型:{0}", bulletConfig.BulletType); break; } if (result != null) { _readyBullets.Add(result); } return result; } public ViewBullet EmitBullet(int bulletId, GameUnit targetUnit, GameUnit sender) { var bulletConfig = GetConfigById(bulletId); if (bulletConfig == null) { DebugUtil.LogError("不存在的子弹配置:{0}", bulletId); return null; } return EmitBullet(bulletConfig, targetUnit, sender); } public ViewBullet EmitBulletFromSummon(int bulletId, int cellIndex, BaseSummon summon) { return EmitBullet(bulletId, cellIndex, summon.creator); } public ViewBullet EmitBulletFromSummon(int bulletId, GameUnit target, BaseSummon summon) { return EmitBullet(bulletId, target, summon.creator); } public ViewBullet EmitBullet(int bulletId, int cellIndex, GameUnit sender) { var bulletConfig = GetConfigById(bulletId); if (bulletConfig == null) { DebugUtil.LogError("不存在的子弹配置:{0}", bulletId); return null; } ViewBullet result = null; switch (bulletConfig.BulletType) { case EBulletType.DIRECT_DAMAGE: // 直接造成伤害 AddBuffs2CellIndex(cellIndex, sender, bulletConfig); break; case EBulletType.POS_LOCK: // 锁地板 result = _EmitLockPosBullet(cellIndex, sender, bulletConfig); break; case EBulletType.UNIT_LOCK: // 锁单位 result = _EmitLockUnitBullet(cellIndex, sender, bulletConfig); break; default: DebugUtil.LogError("暂未实现的子弹类型:{0}", bulletConfig.BulletType); break; } if (result != null) { _readyBullets.Add(result); } return result; } private ViewBullet _EmitLockUnitBullet(GameUnit targetUnit, GameUnit sender, DataBullet bulletConfig) { var bullet = new ViewBullet(bulletConfig, sender); if (!BulletManagerHelper.CheckBulletFilter(sender, targetUnit, bulletConfig)) { bullet.LockPos(targetUnit.transData.cellIndex); return bullet; } bullet.LockUnit(targetUnit); return bullet; } private ViewBullet _EmitLockUnitBullet(int targetCellIndex, GameUnit sender, DataBullet bulletConfig) { var bullet = new ViewBullet(bulletConfig, sender); var units = AreaManager.instance.GetUnitsByCellIndex(targetCellIndex); var isLocked = false; for (var i = 0; i < units.Count; ++i) { var unit = units[i]; if (!BulletManagerHelper.CheckBulletFilter(sender, unit, bulletConfig)) { continue; } bullet.LockUnit(unit); isLocked = true; break; } if (!isLocked) { // 如果没有目标,锁地板 DebugUtil.LogError("目标错误.保护处理,锁定当前地板"); bullet.LockPos(targetCellIndex); } return bullet; } public void PreSelectUnits(int cellIndex, int bulletId, GameUnit sender, List selectUnits) { var bulletConfig = GetConfigById(bulletId); if (bulletConfig == null) return; var units = AreaManager.instance.GetUnitsByCellIndex(cellIndex); for (var i = 0; i < units.Count; ++i) { var unit = units[i]; if (BulletManagerHelper.CheckBulletFilter(sender, unit, bulletConfig)) { selectUnits.Add(unit); } } } private ViewBullet _EmitLockPosBullet(int targetCellIndex, GameUnit creator, DataBullet bulletConfig) { var bullet = new ViewBullet(bulletConfig, creator); bullet.LockPos(targetCellIndex); return bullet; } public void AddBuffs2Unit(GameUnit unit, GameUnit creator, DataBullet bulletConfig) { var sender = creator; if (!BulletManagerHelper.CheckBulletFilter(sender, unit, bulletConfig)) { return; } _CreateNoLineBullet(bulletConfig, creator, unit); if (bulletConfig.LightDuring > 0) { var cellIndex = unit.transData.cellIndex; BlackAreaManager.instance.LightUpCell(cellIndex, bulletConfig.LightDuring); } } public void AddBuffs2CellIndex(int targetCellIndex, GameUnit creator, DataBullet bulletConfig) { var areaId = bulletConfig.AreaId; if (areaId == -1) { // 做全局处理 var units = GameUnitManager.instance.infightUnits.unitList; for (var i = 0; i < units.Count; ++i) { var unit = units[i]; AddBuffs2Unit(unit, creator, bulletConfig); } } else { var cellIndexs = AreaManager.instance.GetCellIndexs(targetCellIndex, areaId); for (var i = 0; i < cellIndexs.Count; ++i) { var cellIndex = cellIndexs[i]; // 根据filterType 和 cellIndex进行处理 var units = AreaManager.instance.GetUnitsByCellIndex(cellIndex); for (var j = 0; j < units.Count; ++j) { var unit = units[j]; AddBuffs2Unit(unit, creator, bulletConfig); } } } } private void _CreateNoLineBullet(DataBullet bulletConfig, GameUnit creator, GameUnit beHitter) { var buffIdList = bulletConfig.BuffList; for (var i = 0; i < buffIdList.Count; ++i) { var buffId = buffIdList[i]; var addBuff = BuffManager.instance.CreateBuffById(creator, buffId); if (addBuff == null) { continue; } BuffManager.instance.AddBuff(beHitter, addBuff); } } public DataBullet GetConfigById(int id) { return TableManager.Instance.Tables.BulletConfig.Get(id); } } }