查看: 1963|回复: 5
打印 上一主题 下一主题

物体合并实现步骤及代码

[复制链接]

5552

主题

2

听众

8万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
11

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

跳转到指定楼层
楼主
发表于 2011-11-2 17:53:00 |只看该作者 |倒序浏览

          I made a simple (but effective) object pooling system that I want to share. If you're after code, scroll down a bit, because here is where I put in the obligatory "what I understand of the topic" spiel, in my own noobish words:
         
           Let's say that in my game I have a turret which shoots missiles. Each of those missiles is a GameObject, and over the course of a single gameplay session that turret might shoot thousands of missiles, each of which is only 'active' for less than a second before it hits its target and is destroyed. The missiles are small, they don't take up a lot of memory, and we can have hundreds of them on-screen without impacting on performance. Woot.
         

           The act of creating and destroying GameObjects, however, is expensive.
         

           To prevent each of those missiles sitting around in memory forever and taking up unnecessary space, Unity will perform a process called Garbage Collection, where it scans all of the GameObjects in memory and figures out which of those missiles is no longer being used before clearing their allocated memory. Garbage Collection can cause noticeable hickups in the framerate of a game. To make matters worse, Unity decides when to perform a Garbage Collection based on how many GameObjects have been created (or memory allocated). So by rapidly firing hundreds and thousands of missiles from our turret, Unity is going to want to Garbage Collect frequently.
         

           Object-pooling aims to rectify the problem through a couple of simple practices. Firstly, if we can pre-allocate a number of objects before gameplay begins, then we can hide the performance hickup caused by GameObject creation in a loading screen (or mission debriefing, or similar non-active screen). Also, rather than destroying a GameObject when it is no longer needed, we can just turn it off (i.e. make it invisible and move it out of the way somewhere) until we need another one.
         

           A robust object-pooling system should include some control over how many of a particular object should be pre-allocated, and how long they should be kept in the pool for. We might only need 10 to 20 missiles for our turret, as that may be the maximum number of missiles that can be in the air at any one time, so pre-allocating a thousand missiles would make no sense. Similarly, some objects might take up a lot of memory, and those we might prefer to only allocate when needed, but keep around for a while as they may be needed again within a short time frame.
         

           The following object-pooling system I've created is simple. I'm sure there are better, more robust options out there, and ways in which to improve the performance of this one. But it works!
         

           Currently, it allows you to define how many of a particular GameObject should be pre-allocated, the maximum number which should be kept in memory indefinitely, and how often the pool should be checked for GameObjects exceeding that maximum number which should be destroyed. So, using the turret example: We could pre-allocate 20 missiles which are created on level load. The turret will use those 20 missiles, grabbing them from the pool when firing, and returning them to the pool when they hit the target. If suddenly our rate of fire changes and the pool becomes empty, new missiles will be created as needed. Every 'n' seconds, the pool will be checked for excess missiles which are no longer being used and destroy them. This allows me to optimise my game to find a balance between memory use and performance.
         

           To use this system:
         

           1. Create two new prefabs (containing empty GameObjects) called GOPool and PoolObject.
         

           2. Assign the two scripts below to the corresponding prefabs.
         

           3. Drag-and-drop a GOPool to the hierarchy view. This is your pool manager. You can pull an object from the pool using GOPool.Instance.Pop(string nameOfPrefab). You return an object to the pool using GOPool.Instance.Push(GameObject reference).
         

           4. To create a pool of objects, drag-and-drop a PoolObject to the hierarchy view. Assign a Prefab directly from the project view, and define the pre-allocation count, maximum storage, and destroy frequency. Then drag-and-drop the PoolObject onto the GOPool's pool collection in the inspector. Repeat as necessary.
         

           That should do it! There may be errors depending on how you use it. I haven't spent much time making sure it's robust or scenario independent. But hopefully someone can make some use of it. It works perfectly for me!
           

           下面为两段代码:
         

           /// <summary>
         

           /// ? Boon Cotter
         

           /// You are granted non-exclusive license to do whatever
         

           /// you want with this code.
         

           /// </summary>
         

           public class GOPool : MonoBehaviour
         

           {
         

           #region Static
         

           /// <summary>
         

           /// Static GOPool instance.
         

           /// </summary>
         

           public static GOPool Instance;
         

           #endregion
         

           #region Fields
         

           /// <summary>
         

           /// The PoolObject collection.
         

           /// </summary>
         

           public List<oolObject> PoolCollection;
         

           /// <summary>
         

           /// The post-build collection.
         

           /// </summary>
         

           private Dictionary<string, PoolObject> Pool;
         

           #endregion
         

           #region Methods
         

           /// <summary>
         

           /// Local initialization.
         

           /// </summary>
         

           private void Awake()
         

           {
         

           if (Instance != null)
         

           Destroy(this);
         

           Instance = this;
         

           Pool = new Dictionary<string, PoolObject>();
         

           foreach (PoolObject po in PoolCollection)
         

           Pool.Add(po.Prefab.name, po);
         

           // Free memory
         

           PoolCollection = null;
         

           }
         

           /// <summary>
         

           /// Get a GameObject from the Pool. Returns null if the Pool does not contain
         

           /// any GameObjects with the specified name.
         

           /// </summary>
         

           public GameObject Pop(string prefabName)
         

           {
         

           PoolObject po;
         

           if (Pool.TryGetValue(prefabName, out po))
         

           return po.Pop();
         

           else
         

           return null;
         

           }
         

           /// <summary>
         

           /// Return a GameObject to the Pool.
         

           /// </summary>
         

           public void Push(GameObject gameObject)
         

           {
         

           PoolObject po;
         

           if (Pool.TryGetValue(gameObject.name, out po))
         

              po.Push(gameObject);
         

           else
         

              Debug.LogError("Trying to push a game object into the GOPool when no collection exists for the type " + gameObject.name + ".");
         

           }
         

           #endregion
         

           }
           

           第二段代码:
         

           /// <summary>
         

           /// ? Boon Cotter
         

           /// You are granted non-exclusive license to do whatever
         

           /// you want with this code.
         

           /// </summary>
         

           public class PoolObject : MonoBehaviour
         

           {
         

           #region Fields
         

           /// <summary>
         

           /// The Prefab to be pooled.
         

           /// </summary>
         

           public GameObject Prefab;
         

           /// <summary>
         

           /// The number of Prefab instances to pre allocate.
         

           /// </summary>
         

           public int PreAlloc = 10;
         

           /// <summary>
         

           /// The maximum number of Prefab instances to maintain.
         

           /// </summary>
         

           public int MaxStore = 10;
         

           /// <summary>
         

           /// The frequency at which unwanted Prefabs exceeding the maximum are destroyed.
         

           /// </summary>
         

           public float DestroyDelay = 5f;
         

           /// <summary>
         

           /// Stores a collection of recycleable GameObjects.
         

           /// </summary>
         

           private Stack<GameObject> Pool;
         

           #endregion
         

           #region Methods
         

           /// <summary>
         

           /// Global Initialize.
         

           /// </summary>
         

           private void Awake()
         

           {
         

           if (Prefab == null)
         

           Debug.LogError("ERROR: PoolObject can not have a null reference for Prefab.");
         

           Pool = new Stack<GameObject>();
         

           for (int n = 0; n < PreAlloc; n++)
         

           {
         

           GameObject go = Instantiate(Prefab, Vector3.zero, Quaternion.identity) as GameObject;
         

           go.name = Prefab.name;
         

           Disable(go);
         

           Pool.Push(go);
         

           }
         

           InvokeRepeating("oll", DestroyDelay, DestroyDelay);
         

           }
         

           /// <summary>
         

           /// Get a GameObject from the stack, or create a new one if the stack is empty.
         

           /// </summary>
         

           public GameObject Pop()
         

           {
         

           GameObject go;
         

           if (Pool.Count > 0)
         

           {
         

           go = Pool.Pop();
         

           Enable(go);
         

           }
         

           else
         

           {
         

           go = Instantiate(Prefab, Vector3.zero, Quaternion.identity) as GameObject;
         

           go.name = Prefab.name;
         

           }
         

           return go;
         

           }
         

           /// <summary>
         

           /// Return a Unit to the stack.
         

           /// </summary>
         

           public void Push(GameObject gameObject)
         

           {
         

           Pool.Push(gameObject);
         

           Disable(gameObject);
         

           }
         

           /// <summary>
         

           /// Disable the specified GameObject.
         

           /// </summary>
         

           private void Disable(GameObject gameObject)
         

           {
         

           gameObject.GetComponentInChildren<Renderer>().enabled = false;
         

           gameObject.SetActiveRecursively(false);
         

           }
         

           /// <summary>
         

           /// Enable the specified GameObject.
         

           /// </summary>
         

           private void Enable(GameObject gameObject)
         

           {
         

           gameObject.SetActiveRecursively(true);
         

           gameObject.GetComponentInChildren<Renderer>().enabled = true;
         

           }
         

           /// <summary>
         

           /// Poll the PoolObject collection for unecessary GameObjects which can be culled.
         

           /// </summary>
         

           private void Poll()
         

           {
         

           for (int n = 1; n <= Pool.Count - MaxStore; n++)
         

           {
         

           GameObject go = Pool.Pop();
         

           Destroy(go);
         

           }
         

           }
         

           #endregion
         

           }
           

            
         
分享到: QQ好友和群QQ好友和群 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
转播转播0 分享淘帖0 收藏收藏0 支持支持0 反对反对0
回复

使用道具 举报

462

主题

1

听众

31万

积分

首席设计师

Rank: 8Rank: 8

纳金币
2
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

沙发
发表于 2012-2-5 23:18:29 |只看该作者
好`我顶``顶顶
回复

使用道具 举报

1023

主题

3

听众

359

积分

设计实习生

Rank: 2

纳金币
335582
精华
0

最佳新人

板凳
发表于 2012-2-13 23:31:40 |只看该作者
不错啊 经典
回复

使用道具 举报

5969

主题

1

听众

39万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

地板
发表于 2012-3-17 23:19:33 |只看该作者
加精、加亮滴铁子,尤其要多丁页丁页
回复

使用道具 举报

   

671

主题

1

听众

3247

积分

中级设计师

Rank: 5Rank: 5

纳金币
324742
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

5#
发表于 2012-4-8 23:26:16 |只看该作者
路过、路过、快到鸟,列位请继续...ing
回复

使用道具 举报

tc    

5089

主题

1

听众

33万

积分

首席设计师

Rank: 8Rank: 8

纳金币
-1
精华
0

最佳新人 活跃会员 热心会员 灌水之王 突出贡献

6#
发表于 2012-4-24 23:25:46 |只看该作者
既来之,则看之!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

手机版|纳金网 ( 闽ICP备2021016425号-2/3

GMT+8, 2024-11-27 18:29 , Processed in 0.103616 second(s), 28 queries .

Powered by Discuz!-创意设计 X2.5

© 2008-2019 Narkii Inc.

回顶部