Unity中的特效管理器(特效缓存池)
发表于2019-01-25
游戏中普遍都有大量的特效,为了便于管理,写了一个简单的特效管理器。
此管理器用到了一个配置表管理器,在上篇Unity中xml配置表管理器中有介绍。
我们的配置文件的内容应该是这样:
这里是excel的样子,如果使用我前面提供的配置表管理器还需要把它转成xml格式。
此管理器借鉴了缓存池的设计思路,使用一个字典用来存放所有特效对象。在初始化此管理器时,会根据配置表中配置的同时存在数量来创建特效,并加入到缓存池中。
使用特效时,根据配置表中的id在缓存池中寻找空闲的特效,如果没有找到会新新创建一个。
下面是管理器的代码:
public class GameEffectManager { //特效池 Dictionary<int ,List<GameEffect>> effectPool = new Dictionary<int ,List<GameEffect>>(); public GameEffectManager(){ //创建特效,加入到池里 List<conf_effect> _conf = ConfigManager.confEffectManager.datas; for(int i = 0 ; i < _conf.Count ; i ++){ conf_effect conf = _conf[i]; for(int j = 0 ; j < conf.repeat_count ; j++){ CreateEffect(conf); } } } /// <summary> /// 添加特效到世界 /// </summary> /// <returns>The world effect.</returns> /// <param name="effectid">配置表中的id.</param> /// <param name="pos">出生位置.</param> /// <param name="scale">特效的尺寸.</param> public GameEffect AddWorldEffect(int effectid,Vector3 pos, float scale){ GameEffect ge = GetEffect(effectid,pos); if(ge == null) return null; ge.transform.position = pos; ge.Play(scale); return ge; } /// <summary> /// 添加特效到指定物体 /// </summary> /// <returns>The effect.</returns> /// <param name="effectid">配置表中的id.</param> /// <param name="obj">跟随物体,如果此物体不为空,特效会跟随此体移动,直到父物体变为null.</param> /// <param name="pos">特效在obj中的相对坐标(偏移).</param> /// <param name="scale">特效的尺寸.</param> public GameEffect AddEffect(int effectid, GameObject obj, Vector3 pos, float scale){ if(obj == null){ return AddWorldEffect(effectid,pos,scale); } GameEffect ge = GetEffect(effectid,obj.transform.position + pos); if(ge == null) return null; ge.SetParent(obj); ge.Play(scale); return ge; } GameEffect GetEffect(int effectid ,Vector3 worldPos){ //对应池是否存在 if(!effectPool.ContainsKey(effectid)){ return null; } //寻找空闲特效 List<GameEffect> pool = effectPool[effectid]; GameEffect ret = null; for(int i = 0 ; i < pool.Count ; i ++){ GameEffect eff = pool[i]; if(eff.gameObject.activeSelf){ continue; } ret = eff; break; } //如果没有可用特效,则创建一个新的 if(ret == null){ conf_effect conf = ConfigManager.confEffectManager.GetData(effectid); if(conf != null) ret = CreateEffect(conf); } return ret; } //添加一个特效到缓存池 GameEffect CreateEffect(conf_effect effect){ Object obj = Resources.Load(effect.file_path); if(obj == null){ Debug.LogError("cant find file ! : " + effect.file_path); } if(effect.res_type == 1){ GameObject go = (GameObject)MonoBehaviour.Instantiate(obj); GameEffect ge = go.AddComponent<GameEffect>(); ge.Init(effect); if (!effectPool.ContainsKey(effect.id)) { effectPool.Add(effect.id, new List<GameEffect>()); } effectPool[effect.id].Add(ge); return ge; } return null; } }
这里只对外提供了2个创建特效的方法,一种是添加到世界的特效,特效播放完即隐藏,另一种是跟随父物体的特效,特效会一直存在直到父物体消失。
这里在创建特效时还会自动赋给特效一个脚本,来控制特效自身的逻辑,该脚本的代码如下:
public class GameEffect : MonoBehaviour { //配置文件 public conf_effect conf{get;private set;} //粒子系统 ParticleSystem ps ; //播放时间 float playTime; //跟随物体,如果此物体不为空,特效会跟随父物体移动,直到父物体变为null public GameObject parent; public void Init(conf_effect conf){ this.conf = conf; ps = transform.GetComponent<ParticleSystem>(); gameObject.SetActive(false); } public void Play(float scale){ playTime = 0; gameObject.SetActive(true); ps.Play(); SetScale(transform, scale); } public void SetScale(Transform t, float scale){ for (int i = 0; i < t.childCount; i ++){ SetScale(t.GetChild(i),scale); } t.localScale = new Vector3(scale, scale, scale); } void Update(){ playTime += Time.deltaTime; if (parent != null) { transform.position = parent.transform.position; return; } if(playTime > ps.main.duration){ Die(); } } public void SetParent(GameObject obj){ this.parent = obj; } public void Die(){ gameObject.SetActive(false); } void OnDestroy(){ } }
使用方法
游戏开始时我们需要先创建管理器:
GameEffectManager gameEffectManager = new GameEffectManager();
我们只需要调用创建方法就可以使用特效了:
gameEffectManager.AddEffect(60010010,ojb,pos,1.0);
这样我们不用关心特效的创建和消失的细节,使用起来还是很方便的。在实际的项目开发中,可能还需要根据项目的不同需求进行一些修改。