using System; using System.Collections.Generic; using System.Linq; using UnityEngine; public class ActorInfo : MonoBehaviour { //[RuntimeInitializeOnLoadMethod] //static void OnRuntimeMethodLoad() { new GameObject("ActorInfo").AddComponent(); } public static ActorInfo Ins; private void Awake() { Ins = this; DontDestroyOnLoad(gameObject); } private ObjectPool> listPool = new ObjectPool>(); /// /// 역할, 스포너id, 프리팹이름 /// Dictionary>>> dic_actor = new Dictionary>>>(); List destroylst = new List { eRole.PC, eRole.Pet, eRole.Fairy, eRole.Mob, eRole.BattleNPC, eRole.OBJ, eRole.Farmer }; public void Destroy_Mobs() { foreach (var role in destroylst) { // dic_actor 딕셔너리에서 destroylst에 포함된 역할(eRole)에 해당하는 항목만 처리 if (dic_actor.ContainsKey(role)) { // 역할에 해당하는 그룹들을 가져옴 var groupDict = dic_actor[role]; foreach (var groupEntry in groupDict) { // 그룹 내의 모든 MobActor 리스트를 비움 foreach (var prefabEntry in groupEntry.Value) { foreach (var mobActor in prefabEntry.Value) { if (mobActor != null) { // mobActor 게임 오브젝트를 제거 Destroy(mobActor.gameObject); } } // 해당 리스트를 비움 prefabEntry.Value.Clear(); } } } } } public void All_Stop(bool _stop) { foreach (var item in dic_actor) { foreach (var item2 in item.Value) { foreach (var actorlst in item2.Value.Values) { foreach (var actor in actorlst) { actor.Stop(_stop); } } } } } public void All_DelTarget() { foreach (var item in dic_actor) { foreach (var item2 in item.Value) { foreach (var actorlst in item2.Value.Values) { foreach (var actor in actorlst) { actor.Del_Target(); } } } } } public MobActor Get_ReMobActor(int spawnerId, eRole role, string prefab) { // 몹 재사용 Check_ActorDic(spawnerId, role, prefab); var actor = dic_actor[role][spawnerId][prefab].Find(f => !f.isActiveAndEnabled); return actor ? actor as MobActor : null; } void Check_ActorDic(int spawnerId, eRole role, string prefab) { if (!dic_actor.ContainsKey(role)) dic_actor.Add(role, new Dictionary>>()); if (!dic_actor[role].ContainsKey(spawnerId)) dic_actor[role].Add(spawnerId, new Dictionary>()); if (!dic_actor[role][spawnerId].ContainsKey(prefab)) dic_actor[role][spawnerId].Add(prefab, new List()); } public void Add_Actor(Actor actor, eRole role, int spawnerId, string prefabName) { // 생성한 액터 추가 Check_ActorDic(spawnerId, role, prefabName); dic_actor[role][spawnerId][prefabName].Add(actor); } public void All_Heal(float rate) { foreach (var item in dic_actor[eRole.PC][0]) item.Value.ForEach(f => f.Heal(rate)); foreach (var item in dic_actor[eRole.Pet][0]) item.Value.ForEach(f => f.Heal(rate)); foreach (var item in dic_actor[eRole.Summon][0]) item.Value.ForEach(f => f.Heal(rate)); } public void Release_Actors(List actors) { actors.Clear(); listPool.Release(actors); } public List Get_Actors(eRole role, int spanwerId = 0, bool includeDie = false, bool _onlyBerserkPet = false) { var actors = listPool.Get(); if (!dic_actor.ContainsKey(role)) return actors; foreach (var item in dic_actor[role][spanwerId]) { foreach (var actor in item.Value) { if (includeDie || !actor.IsOnlyDead()) { if (_onlyBerserkPet) { if (actor.IsBerserkPet()) actors.Add(actor); } else actors.Add(actor); } } } return actors; } public void Get_Summon(string prefab, eRole role, eSummon stype, Action act) { Check_ActorDic(0, role, prefab); foreach (var item in dic_actor[role][0]) { foreach (var actor in item.Value) { if (!actor.isActiveAndEnabled && (actor as SummonActor).SummonType == stype) { act(actor); return; } } } AddrResourceMgr.Ins.LoadObject($"Assets/Res_Addr/Summon/{prefab}.prefab", handle => { Actor a = DSUtil.Get_Clone(handle.Result, transform); dic_actor[role][0][prefab].Add(a); act(a); }); } public Actor Get_DeadActor_orNull(eRole role, int spawnerId = 0) { foreach (var item in dic_actor[role][spawnerId]) { foreach (var actor in item.Value) { if (actor.IsDead()) return actor; } } return null; } public Actor Get_Actor(eRole role, int spawnerId = 0) { if (dic_actor.ContainsKey(role)) { foreach (var item in dic_actor[role][spawnerId]) { foreach (var actor in item.Value) { return actor; } } } return null; } /// /// 가장 가까운 적 하나를 찾는다. /// public Actor Get_Nearest_EnemyActor_orNull(bool isEnemy, Vector3 pos, float dist = 0f) { var actors = Get_EnemyActors(isEnemy, pos, dist); Actor nearest = null; float minDistance = float.MaxValue; foreach (var actor in actors) { float distance = Vector3.Distance(pos, actor.Get_position()); if (distance < minDistance) { minDistance = distance; nearest = actor; } } Release_Actors(actors); return nearest; } /// /// 특정 거리 내에서 가장 먼 적을 찾는다. /// public Actor Get_Far_EnemyActor_orNull(bool isEnemy, Vector3 pos, float dist = 10f) { var actors = Get_EnemyActors(isEnemy, pos, dist); //return actors.OrderByDescending(a => (pos - a.Get_position()).sqrMagnitude).FirstOrDefault(); Actor far = actors.Count > 0 ? actors[0] : null; if (DSUtil.CheckNull(far)) return null; float farDistSqr = (pos - far.Get_position()).sqrMagnitude; foreach (var actor in actors) { float distanceSqr = (pos - actor.Get_position()).sqrMagnitude; // 제곱 거리 계산 if (distanceSqr > farDistSqr) { farDistSqr = distanceSqr; far = actor; } } Release_Actors(actors); return far; } /// /// 가장 가까운 동맹 하나를 찾는다. /// public Actor Get_NearstAllyActor(bool isEnemy, Vector3 pos, float dist = 0f) { var actors = Get_AlliesActors(isEnemy, pos, dist); Actor nearest = null; float minDistance = float.MaxValue; foreach (var actor in actors) { float distance = Vector3.Distance(pos, actor.Get_position()); if (distance < minDistance) { minDistance = distance; nearest = actor; } } Release_Actors(actors); return nearest; } /// /// dist 가 0 초과면 범위 내의 적들만 찾는다. /// attackType 가 Max가 아닌 경우면 같은 공격 타입의 적들만 찾는다. /// public List Get_EnemyActors(bool isEnemy, Vector3 pos, float dist = 0f, eAttackType attackType = eAttackType.Max) { var actors = listPool.Get(); float distSquared = dist > 0f ? dist * dist : 0f; // 거리 제곱 계산 foreach (var actorGroup in dic_actor.Values) { foreach (var prefabGroup in actorGroup.Values) { foreach (var actorList in prefabGroup.Values) { foreach (var actor in actorList) { // 조기 종료를 통해 조건을 빠르게 확인 //if (actor == null) continue; //if (DSUtil.CheckNull(actor)) continue; if (actor.IsEnemy() == isEnemy) continue; if (actor.isNoseeMob()) continue; if (actor.IsDead() || actor.Is_Immortal()) continue; // 거리 조건 확인 if (distSquared > 0f) { float distanceSquared = (pos - actor.Get_position()).sqrMagnitude; if (distanceSquared > distSquared) continue; } // 공격 타입 조건 확인 if (attackType != eAttackType.Max && attackType != actor.m_AttackType) continue; // 조건을 모두 만족하는 경우 리스트에 추가 actors.Add(actor); } } } } return actors; } //public List Get_EnemyActors(bool isEnemy, Vector3 pos, float dist = 0f, eAttackType attackType = eAttackType.Max) //{ // var actors = listPool.Get(); // foreach (var item in dic_actor) // { // foreach (var groupEntry in item.Value) // { // foreach (var prefabEntry in groupEntry.Value) // { // foreach (var actor in prefabEntry.Value) // { // if (!DSUtil.CheckNull(actor) && actor.IsEnemy() != isEnemy && !actor.IsDead() && !actor.Is_Immortal() && // (dist <= 0f || Vector3.Distance(pos, actor.Get_position()) <= dist)) // { // // 공격 타입 조건을 만족하는지 확인 // if (attackType == eAttackType.Max || attackType == actor.m_AttackType) // actors.Add(actor); // } // } // } // } // } // return actors; //} /// /// dist 가 0 초과면 범위 내의 동맹들만 찾는다. /// public List Get_AlliesActors(bool isEnemy, Vector3 pos, float dist = 0f) { var actors = listPool.Get(); foreach (var item in dic_actor) { foreach (var groupEntry in item.Value) { foreach (var prefabEntry in groupEntry.Value) { foreach (var actor in prefabEntry.Value) { if (!DSUtil.CheckNull(actor) && actor.IsEnemy() == isEnemy && !actor.IsDead() && !actor.Is_Immortal() && (dist <= 0f || Vector3.Distance(pos, actor.Get_position()) <= dist)) { actors.Add(actor); } } } } } return actors; } }