Unity中的特效管理器(特效缓存池)

发表于2019-01-25
评论0 5.1k浏览
游戏中普遍都有大量的特效,为了便于管理,写了一个简单的特效管理器。

此管理器用到了一个配置表管理器,在上篇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);

这样我们不用关心特效的创建和消失的细节,使用起来还是很方便的。在实际的项目开发中,可能还需要根据项目的不同需求进行一些修改。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引