using System; using System.Collections.Generic; 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 }; Actor m_MyWorker; public void Destroy_All() { if (!DSUtil.CheckNull(m_MyWorker)) Destroy(m_MyWorker.gameObject); 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 Destroy_Mob() { // dic_actor 딕셔너리에서 destroylst에 포함된 역할(eRole)에 해당하는 항목만 처리 if (dic_actor.ContainsKey(eRole.Mob)) { // 역할에 해당하는 그룹들을 가져옴 var groupDict = dic_actor[eRole.Mob]; 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) { // 생성한 액터 추가 if (role == eRole.Worker) m_MyWorker = actor; else { 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) { 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()) { 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 (role == eRole.Worker) return m_MyWorker; 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 minDistanceSqr = float.MaxValue; foreach (var actor in actors) { float distanceSqr = (pos - actor.Get_position()).sqrMagnitude; if (distanceSqr < minDistanceSqr) { minDistanceSqr = distanceSqr; 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_Nearest_AllyActor(bool isEnemy, Vector3 pos, float dist = 0f) { var actors = Get_AlliesActors(isEnemy, pos, dist); Actor nearest = null; float minDistanceSqr = float.MaxValue; foreach (var actor in actors) { float distanceSqr = (pos - actor.Get_position()).sqrMagnitude; if (distanceSqr < minDistanceSqr) { minDistanceSqr = distanceSqr; 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; } /// /// 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 || DSUtil.WithInDistance(pos, actor.Get_position(), dist))) { actors.Add(actor); } } } } } return actors; } }