对象池PoolManager

2016/7/1 Unity游戏开发

在Unity中实例化对象是最耗费资源的,在对象池中直接拿到隐藏的对象,来避免频繁的实例化,提高实现的效率,减少消耗的资源,提高游戏的性能。

# 前言:

在Unity中实例化对象是最耗费资源的,在对象池中直接拿到隐藏的对象,来避免频繁的实例化,提高实现的效率,减少消耗的资源,提高游戏的性能。在Raycoz的游戏框架中,PoolManager的方法来源与PoolManager插件方法。

所以美术在做粒子特效的时候要注意3点:

  1. 同屏的粒子数量一定要控制在200以内,每个粒子的发射数量不要超过50个。不然在iPhone4或者一些比较烂的Android手机上就会有问题
  2. 尽量减少粒子的面积,面积越大就会越卡。
  3. 粒子最好不要用Alfa Test(但是有的特效又不能不用,这个看美术吧) 、如下图所示,粒子的贴图用黑底的这种,然后用Particles/Additive 这种Shader,贴图必须要2的幂次方,这样渲染的效率会高很多。个人建议 粒子特效的贴图在64左右,千万不要太大。

# 对象池关注的几个点

  1. 怎么把游戏对象保存进缓存池;
  2. 怎么把游戏对象从缓存池里面去出来;
  3. 如何智能删除缓存池;

# SpawnPool类

作用:创建缓冲池,并缓冲需要的对象

  1. Awake时会调用PoolManager.Pools.Add(this);把自己加入PoolManager中包含4种Transform,AudioSource,ParticleSystem,ParticleEmitter

  2. SpawnPool里面还有一层PrefabPool,一个SpawnPool内部包含一组PrefabPool具体创建池时是先创建PrefabPool,然后加入SpawnPool中。**使用方法:**创建一个空的GameObjcet 接着把Spawn Pool脚本绑上去,然后设置脚本配置。

    • PoolName:缓存池的唯一名称。

    • MatchPoolScale:勾选后实例化的游戏对象的缩放比例将全是1,不勾选择用Prefab默认的。

    • MachPool Layer:勾选后实例化的游戏对象的Layer将用Prefab默认的。

    • Don’t Reparent:勾选后实例化的对象将没有父节点,通通在最上层,建议不要勾选。

    • Don’t Destroy On Load:切换场景不施放对象。

    • Pre-Prefab Pool Options :缓存池列表,意思就是缓存列表里面可以放各种类型的Prefab。右边有个 “+”按钮点击添加。

    • prefab:可以直接把工程里的Prefab直接拖进来。

    • preloadAmount:缓存池这个Prefab的最大保存数量。

    • preloadTime:如果都选表示缓存池所有的gameobject可以“异步”加载。

    • preloadFrames:每几帧加载一个。

    • preloadDelay:延迟多就开始加载。

    • limitInstance:是否开始实例的限制功能。limitInstance是否开启(打钩)的区别:不开启情况:假如此时preloadAmount为1,如果用户想要每隔5秒去Spawn一个缓冲池中的对象,那么当加载第二个prefab对象的时候,缓冲池会再创建一个此对象,如果程序再Spawn,那么还会在产生一个这样的对象,就这样一直产生下去,Spawn几次就产生几个对象!(粒子系统:循环时:Spawn几次,就会产生几个对象,不循环时(循环结束状态为false):会再产生一个对象,如果此时的Spawn速度特别快,并且检测不到前面的对象状态为false,那么可能会产生多个对象,直到检测到前面的几个对象有false状态,那么产生对象到此为止,程序在此几个对象之间来回Spawn!)

    • limit Amount:限制缓存池里最大的Prefab的数量,它和上面的preloadAmount是有冲突的,如果同时开启则以limitAmout为准。

    • limitFIFO:如果我们限制了缓存池里面只能有10个Prefab,如果不勾选它,那么你拿第11个的时候就会返回null。如果勾选它在取第11个的时候他会返回给你前10个里最不常用的那个。此时Limit Amount为1。limitFIFO勾选:那么程序永远使用的是预加载对象,而不会再产生其他对象!当加载第二次的时候,即使第一个对象处于true状态,也使用它,即操作第一个对象!(粒子系统为循环或者不循环时,效果和这一样)limitFIFO不勾选:那么程序永远使用的是预加载对象,而不会再产生其他对象!当加载第二次的时候,那么必须等第一个对象变为false状态,才能使用它!如果过了5s,第一个对象还没变为false状态,那么程序会报错!(粒子系统为循环:会循环下去,只有一个预加载对象,不报错,不循环时:等上一个变为false才能进行第二次,只有一个预加载对象,不报错!)如果limit Amount数量大于1,为10的话。limitFIFO勾选:永远只有10个对象产生,当加载第11个对象时,如果前十个对象没有一个active为false状态,那么程序会选择不常用的那个,从而避免报错!limitFIFO不勾选:永远只有10个对象产生,但是当加载第11个对象时,如果前十个对象没有一个active为false状态,那么程序会报错!(粒子系统,永远只有10个对象,不报错!)

    • cullDespawend:是否开启缓存池智能自动清理模式。

    • cull Above:缓存池自动清理,但是始终保留几个对象不清理。

    • cull Delay:每过多久执行一遍自动清理,单位是秒。

    • cullMaxPerPass:每次自动清理几个游戏对象。

    • Log Messages: 是否打印日志信息

# PreRuntimePoolItem类

1.为缓冲池预加载对象,作用是OnStart时自动进入相应名字的池:这也是PreRuntimePoolItem脚本的作用,SpawnPool下的Options预设必须包含prefabName,并且悬挂PreRuntimePoolItem脚本的对象和SpawnPool脚本下的Options中的预设无关! 2.如果SpawnPool脚本下已经有预设为Cube的对象,并且预加载数量为3,如果此时我们通过PreRuntimePoolItem脚本的作用,也为此缓冲池加载了2个预设为Cube的对象,那么即使PreRuntimePoolItem脚本的Do Not Reparent是否勾选,一旦程序进行Spawn获取,那么这些预加载对象都会被加载到挂有SpawnPool脚本的对象下,如果Spawn50个,那么就会依次激活他们!Despawn On Start为true的不会算在内!若激活后,就销毁。

  1. PoolName:属于的缓冲池名称。
  2. PrefabName:Prefab预设名称。
  3. DespawnOnStart(true):active初始化为false状态。
  4. DoNotReparent(false):是否把节点加入对象池的子节点

# 使用方法

# 1. 通过脚本创建缓冲池,取对象,销毁对象:

public class CreationExample : MonoBehaviour
{
    //要实例化的预设
    public Transform testPrefab;
    //缓冲池的名称
    public string poolName = "Creator";
    //缓冲数量
    public int spawnAmount = 50;
    //多久实例化或者删除一个对象(Interval:时间间隔)
    public float spawnInterval = 0.25f;
    //缓冲池对象
    private SpawnPool pool;

    private void Start()
    {
        //创建缓冲池,并命名
        this.pool = PoolManager.Pools.Create(this.poolName);
        
        //指定这个组的父节点(此时的父节点被指定为当前脚本悬挂的对象,即Creator对象)
        this.pool.group.parent = this.transform;
        //那么从缓冲池获取对象,对象的层次关系为:
        //  Creator
        //  -------CreatorGroup
        //  ---------------------Sphere(Clone)001
        //  ---------------------Sphere(Clone)002
        //  ---------------------Sphere(Clone)003
        //指定这个组(即CreatorGroup)的位置与旋转
        this.pool.group.localPosition = new Vector3(1.5f, 0, 0);
        this.pool.group.localRotation = Quaternion.identity;

        //创建预设
        PrefabPool prefabPool = new PrefabPool(testPrefab);
        //缓存池这个Prefab的最大保存数量
        prefabPool.preloadAmount = 5;
        //是否开启缓存池智能自动清理模式
        prefabPool.cullDespawned = true;
        //缓存池自动清理,但是始终保留几个对象不清理
        prefabPool.cullAbove = 10;
        //每过多久执行一遍自动清理(销毁),单位是秒
        prefabPool.cullDelay = 1;
        //每次自动清理2个游戏对象
        prefabPool.cullMaxPerPass = 2;
        //是否开启实例的限制功能
        prefabPool.limitInstances = true;
        //限制缓存池里最大的Prefab的数量,它和上面的preloadAmount是有冲突的,如果同时开启则以limitAmout为准
        prefabPool.limitAmount = 5;
        //如果我们限制了缓存池里面只能有10个Prefab,如果不勾选它,那么你拿第11个的时候就会返回null。如果勾选它在取第11个的时候他会返回给你前10个里最不常用的那个
        prefabPool.limitFIFO = true;
        //加入此预设
        this.pool.CreatePrefabPool(prefabPool);
        //开启协同,实例化对象
        this.StartCoroutine(Spawner());

    }

    //每隔一段时间实例化一个对象
    private IEnumerator Spawner()
    {
        int count = this.spawnAmount;
        Transform inst;
        while (count > 0)
        {
         // Spawn in a line, just for fun
            inst = pool.Spawn(this.testPrefab, Vector3.zero, Quaternion.identity);
            inst.localPosition = new Vector3(this.spawnAmount - count, 0, 0);
            count--;
            yield return new WaitForSeconds(this.spawnInterval);
        }
        // 开始销毁对象
        this.StartCoroutine(Despawner());
    }

    //每隔一段时间销毁一个对象
    private IEnumerator Despawner()
    {
        while (pool.Count > 0)
        {
            Transform instance = pool[pool.Count - 1];
            pool.Despawn(instance);

            yield return new WaitForSeconds(this.spawnInterval);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84

2.取缓冲池中的某一个对象

Transform cubePrefab = PoolManager.Pools["Shapes"].prefabs["Cube"];
Transform cubeinstance = PoolManager.Pools["Shapes"].Spawn(cubePrefab);
cubeinstance.name = "Cube (Spawned By CreationExample.cs)"; 
1
2
3
Last Updated: 2022/1/8 04:00:18