Unity GC优化学习(三):对象池技术与PoolManager插件
来源:互联网 发布:ae渲染快捷键 mac 编辑:程序博客网 时间:2024/05/20 15:41
1.简介
对象池技术——是一种广泛通用的内存优化手段。在首次建立对象时,便将其存储在池子中,需要再次使用时,不是每次都实例化一个新的对象,而是查找回收池中是否存在闲置的对象,将其重新激活利用。
2.简单对象池的实现
单个预支体的对象池
using UnityEngine;using System.Collections;using System.Collections.Generic;namespace Farther{ public class PrefabPool{ #region Public Properties Available in the Editor public SpwanPool spawnPool; public Transform prefab; internal GameObject prefabGO; /// <summary> /// 最多可以存在的实例个数,如果超过这一上限,则会强制回收重用最早激活的实例 /// </summary> public int maxAmount; #endregion Public Properties Available in the Editor #region Constructor and Self-Destruction public PrefabPool(Transform prefab) { this.prefab = prefab; this.prefabGO = prefab.gameObject; _spawned = new List<Transform> (); _despawned = new List<Transform>(); } /// <summary> /// 供Editor构建界面使用 /// </summary> public PrefabPool() { } internal void SelfDestruct() { this._despawned.Clear (); this._spawned.Clear (); this.prefab = null; this.prefabGO = null; this.spawnPool = null; } #endregion Constructor and Self-Destruction #region Pool Functionality internal List<Transform> _spawned; internal List<Transform> _despawned; public int totalCount { get { int count = 0; count += this._spawned.Count; count += this._despawned.Count; return count; } } internal void inspectorInstructor() { this.prefabGO = this.prefab.gameObject; this._spawned = new List<Transform> (); this._despawned = new List<Transform> (); } internal Transform SpawnInstance(Vector3 pos, Quaternion rot) { if (this._spawned.Count >= maxAmount) { Transform firstIn = this._spawned [0]; this.DespawnInstance (firstIn); } Transform inst; if (this._despawned.Count == 0) { Debug.Log ("_despawned.Count == 0"); inst = this.SpawnNew (pos,rot); } else { inst = this._despawned [0]; this._despawned.RemoveAt (0); this._spawned.Add (inst); inst.position = pos; inst.rotation = rot; inst.gameObject.SetActive (true); } return inst; } internal bool DespawnInstance(Transform xform) { if(this._spawned.Contains(xform)) { //否则说明该对象已经被despawn了 if (this._spawned.Contains (xform)) { this._spawned.Remove (xform); this._despawned.Add (xform); xform.gameObject.SetActive (false); } } return true; } internal Transform SpawnNew(Vector3 pos,Quaternion rot) { Transform inst = (Transform)Object.Instantiate (this.prefab, pos, rot); this._spawned.Add (inst); return inst; } /// <summary> /// 在该“池中”的_spawned 以及 _despawned 中查找,是否存在目标物体 /// </summary> /// <param name="instance">Instance.</param> public bool Contain(Transform instance) { bool contains =false; contains = _spawned.Contains (instance); if (contains) return true; contains = _despawned.Contains (instance); if (contains) return true; return false; } #endregion Pool Functionality }}
管理多个预制体的对象池
using UnityEngine;using System.Collections;using System.Collections.Generic;namespace Farther{ [AddComponentMenu("Custom/SpawnPool")] //[ExecuteInEditMode] public sealed class SpwanPool : UnitySingleton<SpwanPool> { public string poolName; /// <summary> /// 是否默认将生成的物体的父物体放置到Group下 /// </summary> public bool isDefaultGroup; public Transform group { get; private set; } public List<PrefabPool> perPrefabPoolOptions = new List<PrefabPool>(); public Dictionary<object,bool> _editorListItemStates = new Dictionary<object, bool>(); /// <summary> /// 得到只读的预制体池,每次回调用都会产生额外的内存分配,慎用! /// </summary> /// <value>The read only prefab pools.</value> public Dictionary<string ,PrefabPool> readOnlyPrefabPools { get { Dictionary<string,PrefabPool> dic = new Dictionary<string, PrefabPool> (); foreach (PrefabPool pool in m_PrefabsPools) { dic [pool.prefabGO.name] = pool; } return dic; } } private Dictionary<string,PrefabPool> m_PrefabPoolsDic = new Dictionary<string, PrefabPool>(); /// <summary> /// Gets the prefab pools. /// </summary> /// <value>The prefab pools.</value> public Dictionary<string ,PrefabPool> PrefabPools { get { m_PrefabPoolsDic.Clear (); foreach (PrefabPool pool in m_PrefabsPools) { m_PrefabPoolsDic [pool.prefabGO.name] = pool; } return m_PrefabPoolsDic; } } private List<PrefabPool> m_PrefabsPools = new List<PrefabPool>(); internal List<Transform> _spawned = new List<Transform>(); internal List<Transform> _despawned = new List<Transform>(); void Awake() { group = this.transform; gameObject.name = "Group"; //对编辑器界面的定义的prefab pool进行初始化 for (int i = 0; i < perPrefabPoolOptions.Count; i++) { if (perPrefabPoolOptions [i].prefab == null) { Debug.LogError ("对象池中的预制体为空!"); continue; } this.perPrefabPoolOptions [i].inspectorInstructor (); } } public Transform Spawn(Transform prefab,Vector3 pos,Quaternion rot,Transform parent) { for (int i = 0; i < m_PrefabsPools.Count; i++) { if (m_PrefabsPools [i].prefabGO == prefab.gameObject) { Transform inst = m_PrefabsPools [i].SpawnInstance (pos, rot); if (parent != null) { ///同样也会适配RectTransform bool worldPositionStays = !(inst is RectTransform); inst.SetParent (parent, worldPositionStays); } else if(isDefaultGroup) { bool worldPositionStays = !(inst is RectTransform); inst.SetParent (this.group, worldPositionStays); } return inst; } } return null; } public void Despawn(Transform instance) { bool isDespawned = false; for (int i = 0; i < this.m_PrefabsPools.Count; i++) { if (m_PrefabsPools [i].Contain (instance)) { m_PrefabsPools [i].DespawnInstance (instance); return; } } Debug.LogError ("无法在对象池中找到该实例!!!!"); } public PrefabPool AddPrefabPool(Transform prefab) { PrefabPool prefabPool = new PrefabPool (prefab); prefabPool.spawnPool = this; m_PrefabPoolsDic.Add (prefab.gameObject.name, prefabPool); m_PrefabsPools.Add (prefabPool); return prefabPool; } }}
使用
using UnityEngine;using System.Collections;using Farther;public class ObjPoolTest : MonoBehaviour { public Transform prefab1; public Transform prefab2; public Transform prefab3; // Use this for initialization void Start () { SpwanPool.instance.AddPrefabPool (prefab1).maxAmount = 2; SpwanPool.instance.AddPrefabPool (prefab2).maxAmount = 2; SpwanPool.instance.AddPrefabPool (prefab3).maxAmount = 2; } // Update is called once per frame void Update () { if (Input.GetKeyDown (KeyCode.A)) { SpwanPool.instance.Spawn (prefab1, transform.position, transform.rotation, transform); } if (Input.GetKeyDown (KeyCode.S)) { SpwanPool.instance.Spawn (prefab2, transform.position, transform.rotation, transform); } if (Input.GetKeyDown (KeyCode.D)) { SpwanPool.instance.Spawn (prefab3, transform.position, transform.rotation, transform); } }}
这部分代码只是实现了最为简单的对象池,存在着很多功能上的不足甚至是缺陷,但是对于理解对象池技术或者是PoolMnanger插件都是存在极其重要的意义。
3.PoolManager介绍
国外大神编写,核心脚本只有三个:PoolManager、PreRunTimePoolItem、 SpawnPool,功能非常强大完善,可以调节配置的属性非常多,但是代码量也是不少,上面的代码也只是抽离了其中的一小部分。
4.PoolMananger基础学习
5.案例学习
1.AudioExample
这个例子让我注意到了,插件内部是使用了SendMessage机制,通知具体的对象被激活或被回收,这两个函数【前提一定要声明为公有的】:
public void OnSpawned(SpawnPool pool) public void OnDespawned(SpawnPool pool)
这样就可以订制对象被回收或激活时的行为了。
2.DeleteTest
简单的使用了对象池的创建以及销毁。
3.ExampleScene
使用了PreRunTimePoolItem脚本,场景运行后,这个预先放置好的PoolItem将会更根据PoolName以及PrefabName被管理。
4.OnCreatedDelegateExample
展示了添加对象池创建时的回调,赶脚没啥用。
5.PreloadOverTime
展示了如果随时间匀速生成新的实例。
图中设定为,开启随着时间进行的预加载,预加载总数量为50个,在50帧内加载完成,预加载在该脚本激活后延迟3秒进行。
6.SpaceShooter 官方Demo中实践使用 PoolManger
[初学Unity时,学习的第一个官方Demo,当时还不懂得任何内存管理的知识,回首发现在这漫漫的学习过程中,自己已经成长进步了那么多了。]
后记:
1.当随时间自动销毁粒子时,发现,OnEnable会在该对象所在的SpawnPool尚未被加入到PoolManager中就被调用,这个很别扭。
so,下面的脚本尝试了好几次:
using UnityEngine;using System.Collections;using PathologicalGames;public class Done_DestroyByTime : MonoBehaviour{ private SpawnPool explosionPool; public float lifetime; private bool initialized = false; void Awake() { initialized = false; } void Start() { Initialize (); } void Initialize() { explosionPool = PoolManager.Pools["ExplosionParticle"]; explosionPool.Despawn (transform, lifetime); initialized = true; } void OnEnable () { if (initialized) { explosionPool.Despawn (transform, lifetime); } }}
2.改动量最大的脚本
using UnityEngine;using System.Collections;using PathologicalGames;public class Done_DestroyByTrigger : MonoBehaviour{ public GameObject asteroidExplosion; public GameObject enemyShipExplosion; public GameObject playerExplosion; public int scoreValue; private Done_GameController gameController; private string enemyTag = "Enemy"; private SpawnPool explosionPool; private SpawnPool enemyShipPool; private SpawnPool playerBoltPool; private SpawnPool enemyAsteroidPool; private SpawnPool enemyBoltPool; void Start () { GameObject gameControllerObject = GameObject.FindGameObjectWithTag ("GameController"); if (gameControllerObject != null) { gameController = gameControllerObject.GetComponent <Done_GameController>(); } if (gameController == null) { Debug.Log ("Cannot find 'GameController' script"); } explosionPool = PoolManager.Pools["ExplosionParticle"]; enemyShipPool = PoolManager.Pools["EnemyShip"]; playerBoltPool = PoolManager.Pools["PlayerBullet"]; enemyAsteroidPool = PoolManager.Pools["Asteroid"]; enemyBoltPool = PoolManager.Pools ["EnemyBullet"]; } void OnTriggerEnter (Collider other) { if (gameObject.CompareTag (Tags.EnemyBolt) || gameObject.CompareTag (Tags.EnemyShip) || gameObject.CompareTag (Tags.EnemyAsteroid)) { OnTriggerEnterEnemy (other); }// Destroy (other.gameObject);// Destroy (gameObject); } void OnTriggerExit(Collider other) { if (gameObject.CompareTag (Tags.Boundary)) { OnTriggerExitBoudary (other); } } void OnTriggerExitBoudary(Collider other) { if (other.gameObject.CompareTag (Tags.EnemyShip)) { enemyShipPool.Despawn (other.transform); } else if (other.CompareTag (Tags.EnemyAsteroid)) { enemyAsteroidPool.Despawn (other.transform); } else if (other.gameObject.CompareTag (Tags.EnemyBolt)) { enemyBoltPool.Despawn (other.transform); } else if (other.gameObject.CompareTag (Tags.PlayerBolt)) { playerBoltPool.Despawn (other.transform); } } void OnTriggerEnterEnemy(Collider other) { if (other.transform.CompareTag (Tags.Player)) { explosionPool.Spawn (playerExplosion, other.transform.position, other.transform.rotation); GameObject.Destroy(other.transform.gameObject); if (gameObject.CompareTag (Tags.EnemyShip)) { enemyShipPool.Despawn (transform); } else if (gameObject.CompareTag (Tags.EnemyAsteroid)) { enemyAsteroidPool.Despawn (transform); } else if (gameObject.CompareTag (Tags.EnemyBolt)) { enemyBoltPool.Despawn (transform); } gameController.GameOver(); } if (other.transform.CompareTag (Tags.Boundary) || other.transform.CompareTag (Tags.EnemyShip) || other.transform.CompareTag (Tags.EnemyAsteroid) || other.transform.CompareTag (Tags.EnemyBolt)) { return; } if (other.transform.CompareTag (Tags.PlayerBolt)) { playerBoltPool.Despawn (other.transform); if (gameObject.CompareTag (Tags.EnemyShip)) { enemyShipPool.Despawn (transform); explosionPool.Spawn (enemyShipExplosion,transform.position, transform.rotation); } else if (gameObject.CompareTag (Tags.EnemyAsteroid)) { enemyAsteroidPool.Despawn (transform); explosionPool.Spawn (asteroidExplosion,transform.position, transform.rotation); } gameController.AddScore(scoreValue); return; } }}
3.在SpawnPool中加入的两个新的自定义函数
/// <summary> /// 随机产生/激活对象池中的某一预制体的实例 /// </summary> /// <returns>The spawn.</returns> /// <param name="pos">Position.</param> /// <param name="rot">Rot.</param> public Transform RandomSpawn(Vector3 pos,Quaternion rot) { int upbound = _prefabPools.Count; int index = Random.Range (0, upbound); PrefabPool pool = _prefabPools [index]; return pool.SpawnInstance (pos,rot); } /// <summary> /// 推荐当对象池中只有一个预支体时使用,激活对象池中最先被加入的预制体 /// </summary> /// <param name="pos">Position.</param> /// <param name="rot">Rot.</param> public Transform Spawn(Vector3 pos,Quaternion rot) { if (_prefabPools.Count > 0) { return _prefabPools [0].SpawnInstance (pos, rot); } Debug.LogError ("对象池为空无法进行任何Spawn!!"); return null; }
4.在SpawnPool中发现了一个比较好用的延迟回收的重载函数
/// <description> /// See docs for Despawn(Transform instance). This expands that functionality. /// If the passed object is managed by this SpawnPool, it will be /// deactivated and made available to be spawned again. /// </description> /// <param name="item">The transform of the instance to process</param> /// <param name="seconds">The time in seconds to wait before despawning</param> public void Despawn(Transform instance, float seconds) { this.StartCoroutine(this.DoDespawnAfterSeconds(instance, seconds, false, null)); }
最后改好的Demo:
http://pan.baidu.com/s/1kVIEg3l
- Unity GC优化学习(三):对象池技术与PoolManager插件
- PoolManager 对象池插件(Unity)的使用
- Unity 插件 缓存PoolManager
- unity对象池工具PoolManager初体验
- unity-PoolManager 预制件管理插件
- Unity GC优化学习(二):Unity内存管理
- Unity PoolManager
- Unity3D PoolManager缓冲池插件
- Unity3D PoolManager缓冲池插件
- Unity3D PoolManager缓冲池插件
- PoolManager插件
- [Unity]Unity性能优化实战之GC优化(序)
- [Unity]Unity性能优化实战之GC优化(1)
- PoolManager缓冲池插件用法整理
- [Unity优化]减少gc
- Unity优化大全(三)之CPU-GC(内存回收)和Sricpt
- [Unity优化]对象池
- PoolManager插件从池子中取出多种对象
- Buy the Ticket
- Linux基本操作系列(二):在CentOS 6.8系统上安装Tomcat并配置自动启动
- POJ1062 昂贵的赠礼 dijkstra
- icons8.com Android图标
- CentOS7.2内核编译安装
- Unity GC优化学习(三):对象池技术与PoolManager插件
- tensorflow 中 sparse_softmax_cross_entropy_with_logits 与 softmax_cross_entropy_with_logits区别
- 现在,以编程方式在 Electron 中上传文件,是非常简单的!
- WebGL之旅(八)纹理映射
- 面向对象程序设计第七次实验课——状态模式
- 阿里云服务器注意事项
- RGB、YUV和YCbCr
- C++ STL之map与unordered_map
- ajax异步获取数据后动态向表格中添加数据(行)