Unity优化之ObjectPool-关于初始化

来源:互联网 发布:淘宝开店分享心得 编辑:程序博客网 时间:2024/06/15 12:41

在Unity制作游戏的使用过程中.发现在游戏中激活大量GameObject的时候会卡顿.还有偶尔没有任何瓶颈的时候也会莫名的卡顿一下.好在有Profiler可以方便的查看到卡顿的点.



帧率稍慢不是问题.但在某一时间点上的卡住就是个很不好的体验.查看发现主要卡顿点在两处地方.

一是Instantiate.尤其是类似Rigdbody的组件.在激活时会更新一些全局的状态.

二是GC.Collect.Unity的自动GC发生的时间是无法控制的.可能发生在任何时间点.


对于一来说可以通过分批激活的方式来解决.比如使用coroutine来挨个激活就可以避免卡顿.

但对于二来说只有避免GC.那就要避免Destory.

综上.如果想避免游戏中的卡顿.首先要使用对象池.重复使用对象.避免对象的销毁.二是在合适的时候手动GC.比如Loading界面.


ObjectPool是很容易实现的.但Unity的Particles和Trail初始化会有一些问题.


简单的ObjectPool : 

public class ObjectPool<T>{private List<T> _objects = new List<T>();public T GetObject(){T item;if( _objects.Count > 0 ){item = _objects[0];_objects.RemoveAt( 0 );return item;}return default(T);}public void PutObject(T item){_objects.Add(item);}public int GetObjectCount(){return _objects.Count;}}


再包装一个ObjectManage.对于不同对象使用不同的Pool

public class ObjectManager {Dictionary< int, Dictionary<int, ObjectPool<GameObject>> >m_BulletsPool;//子弹的对象池public GameObject GetBullet( int iBulletId, int iBulletDisplayId ){if( m_BulletsPool.ContainsKey( iBulletId ) == false )return null;if( m_BulletsPool[iBulletId].ContainsKey(iBulletDisplayId) == false )return null;return m_BulletsPool[iBulletId][iBulletDisplayId].GetObject();}public void RecycleBullet( int iBulletId, int iBulletDisplayId, GameObject objBullet ){if( m_bUseBulletPool == false )return;if( m_BulletsPool.ContainsKey( iBulletId ) == false ){m_BulletsPool.Add( iBulletId, new Dictionary<int, ObjectPool<GameObject>>() );}if( m_BulletsPool[iBulletId].ContainsKey(iBulletDisplayId) == false ){m_BulletsPool[iBulletId].Add( iBulletDisplayId, new ObjectPool<GameObject>() );}objBullet.SetActive( false );m_BulletsPool[iBulletId][iBulletDisplayId].PutObject( objBullet );}}

这样在使用过程中会发现.带Trail的GameObject在重用后.由于没有重置.会在旧的位置和新的位置之间产生拖尾.而带有Particle System的GameObject再重用过程中参数会不断积累.还有其他一些组件.也都需要初始化.

对于Trail.关键是要在回收时将TrailRenderer.time 置为-1.

对于Particle System.应该是要重置所有的属性.

针对以上情况.写了一个组件.挂在每个要初始化的GameObject上



using UnityEngine;using System.Collections;using System.Collections.Generic;using System.Reflection;public class ObjectPoolComponent : MonoBehaviour {Dictionary<Component, Dictionary<PropertyInfo,object>>m_FieldMap = new Dictionary<Component, Dictionary<PropertyInfo, object>>();//T CopyComponent<T>(T original, GameObject destination) where T : Component//{//System.Type type = original.GetType();//Component copy = destination.AddComponent(type);//System.Reflection.FieldInfo[] fields = type.GetFields();//foreach (System.Reflection.FieldInfo field in fields)//{//field.SetValue(copy, field.GetValue(original));//}//return copy as T;//}////void CopyField<T>( T original, T destination ) where T : Component//{//System.Type type = original.GetType();//System.Reflection.FieldInfo[] fields = type.GetFields();//foreach (System.Reflection.FieldInfo field in fields)//{//field.SetValue(destination, field.GetValue(original));//}//}NcCurveAnimation[]m_CurveAnms = null;ParticleSystem[]m_Particles = null;SpriteSheet[]m_SpriteSheets = null;public TrailRenderer[] m_tcs= null;//public float[]m_tcTimes;void Awake(){m_CurveAnms = GetComponentsInChildren<NcCurveAnimation>();m_Particles = GetComponentsInChildren<ParticleSystem>();m_SpriteSheets = GetComponentsInChildren<SpriteSheet>();if( m_Particles != null ){for( int i = 0; i < m_Particles.Length; ++i ){Dictionary<PropertyInfo,object> mapPro = new Dictionary<PropertyInfo, object>();PropertyInfo[] propertyInfos = m_Particles[i].GetType().GetProperties();for( int j = 0; j < propertyInfos.Length; ++j ){if( propertyInfos[j].CanWrite && propertyInfos[j].PropertyType.IsPublic ){mapPro.Add( propertyInfos[j], propertyInfos[j].GetValue( m_Particles[i], null ) );propertyInfos[0].GetValue( m_Particles[i], null );}}if( mapPro.Count > 0 ){m_FieldMap.Add( m_Particles[i], mapPro );}}}m_tcs = GetComponentsInChildren<TrailRenderer>();if( m_tcs != null ){for( int i = 0; i < m_tcs.Length; ++i ){Dictionary<PropertyInfo,object> mapPro = new Dictionary<PropertyInfo, object>();PropertyInfo[] propertyInfos = m_tcs[i].GetType().GetProperties();for( int j = 0; j < propertyInfos.Length; ++j ){if( propertyInfos[j].CanWrite && propertyInfos[j].PropertyType.IsPublic ){mapPro.Add( propertyInfos[j], propertyInfos[j].GetValue( m_tcs[i], null ) );propertyInfos[0].GetValue( m_tcs[i], null );}}if( mapPro.Count > 0 ){m_FieldMap.Add( m_tcs[i], mapPro );}}//m_tcTimes = new float[m_tcs.Length];////for( int i = 0; i < m_tcs.Length; ++i )//{//m_tcTimes[i] = m_tcs[i].time;//}}}void ResetTrails(){if( m_tcs != null ){for( int i = 0; i < m_tcs.Length; ++i ){if( m_FieldMap.ContainsKey( m_tcs[i] ) == false ){continue;}PropertyInfo[] propertyInfos = m_tcs[i].GetType().GetProperties();for( int j = 0; j < propertyInfos.Length; ++j ){if( m_FieldMap[m_tcs[i]].ContainsKey( propertyInfos[j] ) ){propertyInfos[j].SetValue( m_tcs[i], m_FieldMap[m_tcs[i]][propertyInfos[j]], null );}}}//for( int i = 0; i < m_tcs.Length; ++i )//m_tcs[i].time = m_tcTimes[i];}}void RestoreParticles(){if( m_Particles != null ){for( int i = 0; i < m_Particles.Length; ++i ){if( m_FieldMap.ContainsKey( m_Particles[i] ) == false ){continue;}PropertyInfo[] propertyInfos = m_Particles[i].GetType().GetProperties();for( int j = 0; j < propertyInfos.Length; ++j ){if( m_FieldMap[m_Particles[i]].ContainsKey( propertyInfos[j] ) ){propertyInfos[j].SetValue( m_Particles[i], m_FieldMap[m_Particles[i]][propertyInfos[j]], null );}}m_Particles[i].renderer.enabled = true;m_Particles[i].time = 0;m_Particles[i].Clear( true );m_Particles[i].Play( true );}}}void OnEnable(){if( m_CurveAnms != null ){for( int i = 0; i < m_CurveAnms.Length; ++i ){m_CurveAnms[i].ResetAnimation();}}if( m_SpriteSheets != null ){for( int i = 0; i < m_SpriteSheets.Length; ++i ){m_SpriteSheets[i].ResetPlay();}}//在Disable时将粒子发射器和Trail关闭.但unenable时并未进行刷新.所以需要等一帧再重置回来//ResetTrails();//RestoreParticles();Invoke( "ResetTrails", 0.001f );Invoke( "RestoreParticles", 0.001f );}void OnDisable(){if( m_Particles != null ){for( int i = 0; i < m_Particles.Length; ++i ){m_Particles[i].Stop();m_Particles[i].time = 0;m_Particles[i].Clear( true );m_Particles[i].renderer.enabled = false;}}if( m_tcs != null ){for( int i = 0; i < m_tcs.Length; ++i ){if( m_tcs[i] != null ){m_tcs[i].time = -1;}}}}}






0 0
原创粉丝点击