using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using PhxhSDK; namespace Gameplay.Effect { using cfg.EffectCfg; using Cysharp.Threading.Tasks; using Framework; using Gameplay.Pause; using Gameplay.Skill; using Gameplay.Utils; using UnityEngine; public class EffectManager { private static EffectManager _instance; public static EffectManager instance { get { if (_instance == null) { CreateInstance(); } return _instance; } } public static EffectManager CreateInstance() { if (_instance != null) { // DebugUtil.LogError("请勿重复初始化EffectManager"); return _instance; } _instance = new EffectManager(); _instance.Init(); return _instance; } public GameObject rootObj; private List _preloadingEffects; private List _preloadedEffects; private List _playingEffects; private EffectConfig effectConfig; public int forceSetLayer = -1; private Transform _poolParent; private Dictionary> _objPools; public void Init() { rootObj = new GameObject("EffectManager"); _poolParent = new GameObject("EffectPool").transform; _poolParent.gameObject.hideFlags = HideFlags.HideInHierarchy; _poolParent.gameObject.SetActive(false); #if UNITY_EDITOR if (UnityEditor.EditorApplication.isPlaying) { Object.DontDestroyOnLoad(rootObj); Object.DontDestroyOnLoad(_poolParent.gameObject); } else { // 不做处理 } #else Object.DontDestroyOnLoad(rootObj); Object.DontDestroyOnLoad(_poolParent.gameObject); #endif _playingEffects = new List(); _preloadingEffects = new List(); _preloadedEffects = new List(); _objPools = new Dictionary>(); #if UNITY_EDITOR if (!UnityEditor.EditorApplication.isPlaying) { effectConfig = EditorTableManager.instance.tables.EffectConfig; } else { effectConfig = TableManager.Instance.Tables.EffectConfig; } #else effectConfig = TableManager.Instance.Tables.EffectConfig; #endif MonoHelper.instance.AddAction(EActionType.UPDATE, _LogicUpdate); } public async UniTask PreloadEffects(List effectIds = null) { if (effectIds == null) { // 从配表读取 effectIds = new List(); var dataList = effectConfig.DataList; for (var i = 0; i < dataList.Count; ++i) { var data = dataList[i]; effectIds.Add(data.RoleID); } } for (var i = 0; i < effectIds.Count; ++i) { var effectId = effectIds[i]; var config = GetEffectConfigById(effectId); if (config == null) { continue; } if (_preloadedEffects.Contains(effectId)) { continue; } _PreloadEffect(config); } while (_preloadingEffects.Count > 0) { await UniTask.DelayFrame(1); } } private async void _PreloadEffect(DataEffect config) { if (string.IsNullOrEmpty(config.PrefabPath)) { DebugUtil.LogError($"特效表中{config.RoleID} 的 PrefabPath 为空"); return; } _preloadingEffects.Add(config.RoleID); var loadAsset = await AssetManager.Instance.LoadAssetAsync(config.PrefabPath); _preloadingEffects.Remove(config.RoleID); if (loadAsset == null) { DebugUtil.LogError("特效不存在:{0}", config.PrefabPath); return; } _preloadedEffects.Add(config.RoleID); } public DataEffect GetEffectConfigById(int id) { if (effectConfig.DataMap.TryGetValue(id, out var result)) { return result; } DebugUtil.LogError("无效的特效id:{0}", id); return null; } private EffectPlayingData _CreateFromPool(int effectId) { if (_objPools.TryGetValue(effectId, out var objects)) { if (objects.Count > 0) { var obj = objects.Pop(); if (obj.rootObj != null) { obj.state = EEffectState.Playing; obj.rootObj.SetActive(true); return obj; } } } return _CreateNew(effectId); } private static EffectPlayingData _CreateNew(int effectId) { var effectPlayerData = new EffectPlayingData(effectId); effectPlayerData.rootObj = new GameObject(); return effectPlayerData; } public void ReturnEffect(EffectPlayingData effectData) { var effectId = effectData.effectId; if (effectData.rootObj == null) return; effectData.state = EEffectState.Returned; effectData.rootObj.transform.SetParent(_poolParent); effectData.rootObj.SetActive(false); if (_objPools.TryGetValue(effectId, out var objects)) { objects.Push(effectData); } else { objects = new Stack(); objects.Push(effectData); _objPools.Add(effectId, objects); } } public EffectPlayingData PlayEffectById(int id, Vector3 pos = default, Quaternion rot = default, Transform parent = null) { if (parent == null) { parent = rootObj.transform; } var effectPlayerData = _CreateFromPool(id); _playingEffects.Add(effectPlayerData); effectPlayerData.rootObj.transform.SetParent(parent); effectPlayerData.rootObj.transform.SetPositionAndRotation(pos, rot); var config = GetEffectConfigById(id); if (config == null) return effectPlayerData; if (effectPlayerData.state == EEffectState.Error) { effectPlayerData.Load(config.PrefabPath); } if (config.ExistTime > 0) { effectPlayerData.autoDestroy = true; effectPlayerData.remainTime = config.ExistTime; } else { effectPlayerData.autoDestroy = false; } if (forceSetLayer != -1) { effectPlayerData.rootObj.SetLayerEx(forceSetLayer); } return effectPlayerData; } private void _LogicUpdate() { var dt = MonoHelper.instance.deltaTime; if (PauseManager.instance != null) { dt *= PauseManager.instance.globalScale; } for (var i = 0; i < _playingEffects.Count; ++i) { var playEffect = _playingEffects[i]; playEffect.LogicUpdate(dt); if (playEffect.needReturn) { playEffect.Destroy(); _playingEffects.RemoveAt(i); --i; } } } public void ClearPool() { // 遍历所有的对象池,销毁所有的对象 foreach (var pair in _objPools) { var stack = pair.Value; while (stack.Count > 0) { var effectData = stack.Pop(); effectData.RealDestroy(); } } _objPools.Clear(); } public void Dispose() { // 理论上不会进行Dispose MonoHelper.instance.RemoveAction(EActionType.UPDATE, _LogicUpdate); } } }