using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class ProjectileMgr : MonoBehaviourSingletonTemplate { Dictionary> dic_projectile = new Dictionary>(); public bool LoadComplete; protected override void Awake() { base.Awake(); DontDestroyOnLoad(transform.parent.gameObject); } public void AllOff() { #if UNITY_EDITOR if (MyValue.m_MyStageData.m_EnterType == eStageEnterType.Tool || MyValue.m_MyStageData.m_EnterType == eStageEnterType.Tool_Mob) return; #endif foreach (var item in dic_projectile) for (int i = 0; i < item.Value.Count; i++) item.Value[i].gameObject.SetActive(false); } public IEnumerator Co_Load(Action addslidevalue) { LoadComplete = false; var lst = table_projectile.Ins.Get_DataList(); int totalCount = lst.Count; // 슬라이더 35% 사용 float add1value = 0.35f / totalCount; const int batchSize = 10; // 한 번에 10개씩 로드 for (int batchStart = 0; batchStart < totalCount; batchStart += batchSize) { // 🔹 현재 배치의 끝 인덱스 int batchEnd = Mathf.Min(batchStart + batchSize, totalCount); // 🔹 이 배치에서 비동기로 로드할 코루틴 리스트 List coroutines = new List(); // 🔹 병렬로 10개 로드 시작 for (int i = batchStart; i < batchEnd; i++) { var data = lst[i]; if (!dic_projectile.ContainsKey(data.s_Projectile)) dic_projectile.Add(data.s_Projectile, new List()); // 비동기 로드 코루틴 추가 coroutines.Add(StartCoroutine(LoadProjectile(data, add1value, addslidevalue))); } // 🔹 모든 코루틴이 끝날 때까지 대기 foreach (var c in coroutines) yield return c; // 🔹 한 배치 끝날 때마다 살짝 쉬기 (선택 사항) yield return null; } LoadComplete = true; } private IEnumerator LoadProjectile(ProjectileTableData data, float add1value, Action addslidevalue) { bool done = false; yield return AddrResourceMgr.Ins.LoadObjectSequential( $"Ingame/Projectile/{data.s_Projectile}.prefab", prefab => { for (int k = 0; k < data.n_LoadAmount; k++) { var proj = DSUtil.Get_Clone(prefab, transform, Vector3.right * 10000f); #if UNITY_EDITOR if (proj == null) MyEditorDialog.Show_Dialog($"{data.s_Projectile} 투사체에 ProjectileBase 스크립트가 없습니다.", null); #endif proj.Off_AfterOneShot(data); dic_projectile[data.s_Projectile].Add(proj); } addslidevalue?.Invoke(add1value); done = true; }); // 완료될 때까지 대기 (혹시 비동기일 경우 대비) yield return new WaitUntil(() => done); } ProjectileBase Get_Projectile(string projetile) { if (dic_projectile.ContainsKey(projetile)) { for (int i = 0; i < dic_projectile[projetile].Count; i++) { if (!dic_projectile[projetile][i].isActiveAndEnabled) return dic_projectile[projetile][i]; } var newproj = DSUtil.Get_Clone(dic_projectile[projetile][0].gameObject, transform); newproj.gameObject.SetActive(false); newproj.Off_AfterOneShot(dic_projectile[projetile][0].Get_Data()); dic_projectile[projetile].Add(newproj); return newproj; } else Popup.Ins.Set($"{projetile} 투사체가 없습니다. 테이블을 확인해 주세요."); return null; } public void Shoot_Projectile(ProjectileData pdata, Vector3 start, Vector3 end, Actor target, Action act_end) { var crirate = pdata.Hitter != null ? pdata.Hitter.Get_ActorStatInfo().Get_TotalStat(eStat.Cri) : 0; pdata.isCri = DSUtil.RandomTrue(crirate); var proj = Get_Projectile(pdata.s_Projectile); proj.Set(pdata, start, end, target, act_end); } public void Set_Scale(string proj, float scale) { for (int i = 0; i < dic_projectile[proj].Count; i++) dic_projectile[proj][i].Set_Scale(scale); } }